1

My app reads txt files created by the user, and containing the query text, description, input and output, type of query etc. So I can't just make it easier getting data from the DB and elaborate them in java (which I'm more advanced in).

I have a spare_parts table which is an import from an excel file through CSV import in HEIDI SQL.

It's made this way:

+-------------+---------+---------+---------+---------+---------+
| PART NUMBER | MODEL X | MODEL Y | MODEL Z | MODEL 1 | MODEL 2 |
+-------------+---------+---------+---------+---------+---------+
| PART A      |       0 |       0 |       1 |       0 |       0 |
| PART B      |       1 |       0 |       0 |       1 |       0 |
| PART C      |       1 |       1 |       1 |       0 |       0 |
| PART D      |       0 |       0 |       0 |       1 |       1 |
+-------------+---------+---------+---------+---------+---------+

I need to list the models where a certain part is used, for instance: PART C is used to build model X, Y and Z.

I don't want to list all the columns manually, because they are a lot and because they change often.

What do you suggest?

eggyal
  • 122,705
  • 18
  • 212
  • 237
Dani
  • 35
  • 6
  • 2
    What [RDBMS](http://en.wikipedia.org/wiki/Relational_database_management_system) you are using? `RDBMS` stands for *Relational Database Management System*. `RDBMS is the basis for SQL`, and for all modern database systems like MS SQL Server, IBM DB2, Oracle, MySQL, etc... – John Woo Mar 11 '13 at 09:38
  • Mentioning HeidiSQL tipped me off that OP is using MySQL – ppeterka Mar 11 '13 at 09:42
  • @ppeterka: I didn't know heidisql, but it's [homepage](http://www.heidisql.com/) mentions that it supports MySql and MS SQL-Server(edited the tag-wiki accordingly). – Tim Schmelter Mar 11 '13 at 09:44
  • Yup, MySQL. Sorry for that. HeidiSQL may not be known to everybody, my bad. – Dani Mar 11 '13 at 09:47
  • 3
    Can you not normalise your data, such that you have a table of `(model, part)` pairs? – eggyal Mar 11 '13 at 09:50
  • That would be very nice, but here the guys were working like that since ages and the excel file they are using is not huge but pretty big (ca 250 columns and 1500 rows filled with 1 and 0. I don't know a quick way to do what you suggest. – Dani Mar 11 '13 at 09:54
  • @Street: See [my answer](http://stackoverflow.com/a/15335599). Alternatively, [perform the "unpivot" operation in Excel](http://superuser.com/a/78464) prior to import. – eggyal Mar 11 '13 at 09:56

2 Answers2

0

If I have understood properly, you need a many-to-many relationship, since the number of parts associated to each model is variant. I don't know about this heidisql but the technique must be the same.

Basically, what you have is one table for the parts

parts:


id | name


another for the models


id | name


and finally a third table that connects the previous two tables

models_to_parts


id | model_id | part_id


The relation between these tables is:

enter image description here

And your SQL to retrieve what parts are associated to a model should look like:

SELECT models.name, parts.name FROM models

INNER JOIN models_to_parts ON models.id = models_to_parts.model_id
INNER JOIN parts ON models_to_parts.part_id = parts.id

WHERE models.name = "C" -- or whatever condition you want on model or part 

To construct this many-to-many table you'll need to insert models, then parts, and then read both id's to insert a row that connect them.

Take a look here for further info if you want: http://www.tomjewett.com/dbdesign/dbdesign.php?page=manymany.php

bgusach
  • 14,527
  • 14
  • 51
  • 68
  • Err... i think i'm not understanding this, since i have only one table (spare_parts) and it's made as i showed. The table contains already all the parts in the 1st column, and then has a lot of columns which are the models, and where you find a 1, than that means that model has that part inside (which i can easily do) or viceversa that part is used to build that model and others (which i'm having trouble to figure out). – Dani Mar 11 '13 at 10:06
  • 1
    Well, if I haven't misunderstood all you said... the solution you have is not the best. If you can change that table structure and split it into 3 and model a many-to-many, you'll have a very easy and flexible system where you can query what models are associated to what parts, what parts to what models, you name it... it's clearly the way to go. If you can't change the structure, then go for the other solutions people have offered you. But each time you add new parts or models it'll annoying to re-adapt the query. – bgusach Mar 11 '13 at 10:17
0

Normalise your schema:

CREATE TABLE normalised_parts (
  PRIMARY KEY (model, part)
) SELECT 'X' AS model, `PART NUMBER` AS part FROM spare_parts WHERE `MODEL X`
UNION ALL
  SELECT 'Y', `PART NUMBER` FROM spare_parts WHERE `MODEL Y`
UNION ALL
  SELECT 'Z', `PART NUMBER` FROM spare_parts WHERE `MODEL Z`
UNION ALL
  SELECT '1', `PART NUMBER` FROM spare_parts WHERE `MODEL 1`
UNION ALL
  SELECT '2', `PART NUMBER` FROM spare_parts WHERE `MODEL 2`
-- etc.

Then your problem reduces to:

SELECT model FROM normalised_parts WHERE part = 'PART C'

If the model columns are unknown/numerous, you can create the above DDL from the information schema and then prepare and execute it:

SELECT CONCAT('
  CREATE TABLE normalised_parts (
    PRIMARY KEY (model, part)
  ) ', GROUP_CONCAT('
    SELECT ', QUOTE(COLUMN_NAME), ' AS model, `PART NUMBER` AS part',
    ' FROM spare_parts WHERE `', REPLACE(COLUMN_NAME, '`', '``'), '`'
    SEPARATOR '
  UNION ALL'))
INTO  @sql
FROM  INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME   = 'spare_parts'
  AND COLUMN_NAME LIKE 'MODEL %'  -- or whatever is appropriate

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Note that you may need to increase the value of group_concat_max_len, depending on the aggregate length of the column names.

eggyal
  • 122,705
  • 18
  • 212
  • 237
  • Well. I'll get into this and try it on a copy of the tabe, to check the results. Thanks. I was just wandering if there was a kind of function like: SELECT WHERE value = '1' and PART NUMBER = 'PART C' – Dani Mar 11 '13 at 10:12
  • @Street: No, there isn't. One would have to select all columns and then inspect each within one's application. Generally speaking, a normalised schema will greatly simplify operations on relational data. – eggyal Mar 11 '13 at 10:18
  • eggyal, just for me to know, wouldn't it be easier and more maintainable to use a many-to-many to model the associations between models and parts? – bgusach Mar 11 '13 at 10:21
  • @ikaros45: Is that not exactly the relationship that the above table defines? – eggyal Mar 11 '13 at 10:29
  • @eggyal Thank you, much appreciated, i'll follow your suggestion. – Dani Mar 11 '13 at 10:30
  • Yes, but not very flexible and pretty messy to perform queries. If tomorrow another model comes, add columns, change the query, etc. I believe it would be a better solution to reconstruct the implementation of the relationships into a 3-tables many-to-many relationship. So much group_contact, replace, union... looks ghetto compared to a `SELECT ... INNER JOIN ... WHERE` – bgusach Mar 11 '13 at 10:33
  • @ikaros45: I think we're both recommending exactly the same thing; in particular, as stated in my answer, once the suggested manipulations are performed the problem reduces to `SELECT model FROM normalised_parts WHERE part = 'PART C'`. All the remainder of my answer does is guide through how one can convert the existing structure to that which we both recommend. – eggyal Mar 11 '13 at 10:35
  • Uhm, the concept is similar yes. But what happens when tomorrow comes a new model? the structure of the table `spare_parts` is depending on that. Adapt that table -add new column-, reconstruct the `normalised_parts`. Looks like hard maintenance =). – bgusach Mar 11 '13 at 10:49
  • @ikaros45: And how do you construct `models_to_parts` when the new model comes along? It is the same problem. Indeed, your `models_to_parts` and my `normalised_parts` tables are equivalent (except that you use synthetic keys where I use natural ones). – eggyal Mar 11 '13 at 11:06
  • Uhm, when new model comes, you just add it to models and refer it in the many-to-many... because models are not referred in the parts. Yeah, now I understand a little bit better, my model entails not using anymore `spare_parts` as well. The many-to-many table and your normalized are totally equivalent, but separating models and parts gives you the extra flexibility to add and delete elements without changing structure. – bgusach Mar 11 '13 at 11:51
  • @ikaros45: No, I think you misunderstand me. The OP has data in a certain form already and needs to convert it to the normalised form that we both recommend. I have shown a command that will perform this conversion for him, whereas you have not (instead describing in words how he must rebuild his data). If new data still arrives in the old form, your solution suffers the same problem with which you criticise mine. – eggyal Mar 11 '13 at 11:53
  • Yep, you're right. That's quite good a summary. And my solution entails breaking his available structure... which is not what he was looking for. – bgusach Mar 11 '13 at 12:04
  • @eggyal i have an issue ehan trying your code, it says: SQL Error(1054): Unknown column 'SCHEMA_NAME' in 'where clause' Actually there is a SCHEMA_NAME column but in the SCHEMATA table of information_schema. – Dani Mar 14 '13 at 15:26
  • @Street: Apologies, it should have been `TABLE_SCHEMA`. – eggyal Mar 14 '13 at 15:55