Merging 2 tables horizontally - mysql

I have 2 tables Parents and kids in a MySQL DB, I would like to merge these 2 tables
I would like to know how to query both the tables so I get the following result (query), is this possible? if so, how could I do this?

Simple LEFT JOIN does the job
SELECT *
FROM Parents
LEFT JOIN kids
ON Kids.parents = parent.id

This should work(sort of):
SELECT *
FROM Parents
JOIN kids
ON parents.id = kids.parent
That will give you a result where each Child is on its own line though parents of multiple children will be repeated. This is probably a slightly nicer way of doing it. Your way is possible but it is a pain. You can find the answer on here, it is something that is asked fairly often.
Can I also suggest changing your structure?
I would suggest making a single name attribute for parent instead of father and mother and giving each represented person their own DB entry. Then give each kid a "motherId" and a "fatherId" instead of the combined "parents" attribute. Maybe also try to get into the habit of using "attribueId" attributes to clarify your relationships. This should give you a cleaner schema and be much easier to work with. As it is you have a coupled "parents" entity which needlessly links the father and mother or forces a null value to appear. If instead you have a "parent" entity you have much more freedom. It changes your logical 1 to 1 into a 1 to many.

Related

Recommended method to SELECT multiple columns within a nested subquery in mySQL

What methods are recommended for Selecting multiple columns within a nested subquery? It's been a while since I've coded any queries and I'm having some difficulty wrapping my head around this. The specific challenge is on Line 2 of the code below. The IN operand doesn't quite work here (see error message below), and I'm not sure if it's simply a matter of the syntax I'm using, and/or there is a much better way to go about this (i.e. using the HAVING operand or a JOIN statement)
SELECT * FROM Rules WHERE Rules.LNRule_id
IN(SELECT LNRule_id1,LNRule_id2,LNRule_id3,LNRule_id4 FROM Silhouette
WHERE Silhouette.Silhouette_Skirt=(SELECT Silhouette_Skirt FROM Style
WHERE Style.Style_Skirt='$Style_Skirt')
)
The purpose of this query is to SELECT all the relevant rows in table Rules for a particular value in table Style (i.e. $Style_Skirt), which it does by matching it to one of several factors - in this case the garment's Silhouette. What I am therefore trying to do in this portion of the query is SELECT all rows in table Rules who's ID (LNRule_id) matches values in any of the specified columns in table Silhouette
(SELECT LNRule_id1,LNRule_id2,LNRule_id3,LNRule_id4 FROM Silhouette WHERE Silhouette.Silhouette_Skirt=(...))
Edit
There is a many-to-many relationship (each Silhouette has several applicable Rules, and each Rule can apply to several Silhouettes). All the rules reside in the table 'Rules' (one per row), and each rule has an id ('LNRule_id'). The table 'Silhouette' has columns which tell it which rows need to be called from 'Rules' by 'LNRule_id' (LNRule_id1,2,3,4 indicate which Rules should be called, and store the values of the id's for the relevant rows in table 'Rules')
The error message currently being generated by the IN Operand is:
SQLSTATE[21000]: Cardinality violation: 1241 Operand should contain 1
column(s)
I think you want this query
SELECT * FROM Rules r
JOIN Silhouette s
(ON r.LNRule_id=s.LNRule_id1
OR r.LNRule_id=s.LNRule_id2
OR r.LNRule_id=s.LNRule_id3
OR r.LNRule_id=s.LNRule_id4)
JOIN Style st
ON s.Silhouette_Skirt=st.Silhouette_Skirt
WHERE st.Silhouette_Skirt = '$Style_Skirt'
mysql is complaining that on one side of IN you have a single column, and on the other side you have a multi-column rowset. In order for the IN operator to work, the rowset on the right side of IN must have the exact same number of columns as the left side; in this case, one column.
What you are trying to accomplish could perhaps be achieved if you did something like WHERE LNRule_id IN( SELECT LNRule_Id1 ...) OR LNRule_id IN( SELECT LNRule_Id2 ...) OR ... OR ... but the resulting query would be a monstrosity, and its performance would be horrendous. There may be other ways to go about it too, but anything you try will probably be similarly atrocious.
I do not have enough information to be absolutely sure about what I am saying, but it seems to me that the reason why you have this problem is that your database schema is not normalized. Generally, whenever you see a table with a group of columns having names that all begin with the same prefix and end with a number, it means that someone, somewhere, did not normalize their data.
To address the edit in your question, what you have implemented might conceptually be a many to many relationship, but as far as relational databases are concerned, (you know, the science, the theory, the established practices, the approaches necessary to get things to actually work,) it is definitely not a many to many relationship. Many to many relationships are most certainly not implemented with column1, column2, column3, ... columnN. To be sure that I am not making this stuff up, you can read what others say about many to many relationships here:
Many-to-many relations in RDBMS databases
So, my suggestion, if I correctly understand what is going on, would be to introduce a new table, called SilhouetteRules, which contains two columns, silhouette_id and rule_id. This table will implement a many-to-many relationship between silhouettes and your rules. Then of course you get rid of all the rule1, rule2, rule3, etc. columns from Silhouette.
Once you have done that, you can obtain all silhouettes and all rules associated with them using a query like this:
SELECT * FROM Silhouette
LEFT JOIN SilhouetteRules ON
Silhouette.id = SilhouetteRules.silhouette_id
LEFT JOIN Rules ON
SilhouetteRules.rule_id = Rules.id
The above query will yield multiple rows for each silhouette, where the silhouette fields will be identical from row to row, and only the rule fields will differ. Do not be surprised by this, that's how relational databases work.
Given a given_silhouette_id, you can retrieve all rules associated with it using a query like this:
SELECT * FROM Rules
LEFT JOIN SilhouetteRules ON
Rules.id = SilhouetteRules.rule_id
WHERE
SilhouetteRules.silhouette_id = given_silhouette_id
So, you are going to be using this query as a subquery in queries like the one in the question.
Now, regarding the query in the question, I am unable to tell you exactly how you would need to modify it to get it to work with the normalization that I proposed, because I cannot make sense of it. You see, even if you fix the problem that you currently have with SELECT * FROM table WHERE single-column IN multi-column-rowset, there is another problem further down: the WHERE Silhouette.Silhouette_Skirt=(SELECT ... part would not work either, because you cannot compare the value of a column against the result of a select statement. So, I do not know what you are trying to do there. Hopefully, once you normalize your schema and fix the first problem with your query, then the solution to the second problem will become obvious, or you can ask another question on stackoverflow.
P.S. did Mihai's answer work?

Accessing Nested Parent Properties

I believe this is a relatively basic feature of SQL, but unfortunately I'm not managing to think of exactly how it's done, or what it would be called.
Basically, in my current database, we have Areas, which are parts of Districts, which are parts of Zones, which make up a Region.
Along this chain, each parent only has the ID of the next parent, however, I would like to generate a table with all Areas, where every Area has columns for the ID of the District, Zone, and Region of which it's part of. So how would I write this query?
Oracle offers hierarchical querying, where you can say something like
SELECT parent, child, LEVEL
FROM table
START WITH parent IS NULL
CONNECT BY PRIOR child = parent
The START WITH condition identifies the root of the hierarchy, and the CONNECT BY PRIOR clause identifies how to traverse the hierarchy.
MySQL doesn't have this capability, unfortunately.
Well, Laurence(in the comments) responded correctly, I've been out of the SQL game for a bit too long it seems.
So the simple answer would be:
SELECT child.id as ChildID, parent.id as ParentID, grandparent.id as GrandparentID
FROM child JOIN parent JOIN grandparent
WHERE child.parentID = parent.id AND parent.parentID = grandparent.id
Thanks to all who didn't hardcore downvote this terrible question.

Nested queries (dependent queries)

I need to store a family (i.e. some childs of a parent. Those childs have their own childs and so on..)
So, I created a table family that has following structure
id child child_id parent_id
When I save a child, I store a parent_id along with it.
Now,
when I want to fetch all childs of given parent, I can easily do.
select child_id from family where parent_id = <given parent id>
But,
now I want to fetch the complete family (all descendants of a given parent)
i.e.
I want to fetch all childs which have a given parent_id + all childs that are childs of fetched childs in first query and so on.
Can somebody help me ?
I also, thing there could be better way to store the data initially, so I can fetch it later. Can somebody point out a better way ?
You can write a query that will fetch a child and all of its dependants, but first you would need to re-design your table structure and a enforce a protocol when adding new children to make the query work all the time.
Take a look at this very useful article describing and explaining this method
use sub query
select GC.grandchildren,children from children C inner join grandchildren GC
on C.childid=GC.id and
C.childid in
(select child_id from family
where parent_id = <given parent id>)
Regarding your table design, I think your child_id column is redundant, you can just build the hierarchy by setting which is the parent_id of a certain node, and leave the parent_id empty for the root nodes.
Regarding the query for traversing all childs, you can use an approach like the one proposed here (http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/), but it wll mean you will need to follow some conventions in your ids and store a 'path' with each node.
(which will complicate things if you need to insert something in the middle ot the tree)
Other database brands have clauses for this problem (for Oracle, you have the STARTS WITH ... CONNECT BY clause), but none of them are ANSI.
Hope it helps

Which table schema is better?

which structure is better?
table1
postid category1 category2 category3
2 a b d
3 a c null
or
post table
postid
2
3
category_option table
category option
category1 a
category2 b
category3 c
category4 d
option_post table
post option
2 a
2 b
2 d
3 a
3 c
it seems buiding query for first structure is easier than second structure.
These two structures model different things. The first one rigidly allows only (up to) 3 categories (and differentiates between categories by position), while the second one can model any number of categories (which are not distinguished by position). Which one is better really depends on what you are trying to accomplish...
On purely technical level, the second one might require a JOIN for some queries where the first one could satisfy the query from the single (and only) table. Whether this is a problem or not, again, depends on circumstances...
Depends on requirements...
Do you anticipate increasing the number of options over time?
your first option is by far easier to code, the second option is much more modular design and scalable.
It depends greatly on the nature of the categories. If the list is fixed and unlikely to grow, then the first structure works just fine and can be easier to work with. If the list of categories is likely to grow, then the second option will grow better.
It also matters if the category values are sparse. If most of the categories will not have values, then the second approach will take up much less space. If every item will have values in every category, this is not an issue.
It is important in this case to understand what "likely" means. It doesn't mean that you the designer don't think it will grow. It means that the list of categories is well-understood and mature, and so unlikely to grow. I kept looking for examples, but none come to mind.
There are good reasons to select the first, but do so with care - switching to the second option in a production system will be a nightmare.
The second one is better. The first is a violation of First Normal Form:
http://en.wikipedia.org/wiki/First_normal_form#Repeating_groups_across_columns
2nd one better. it's typical many2many with join table case.
if you do it in 1st way, what are you gonna do if there are new category category 4,5,6,7,8... come? add new columns to the table?
And, I don't know if you have a requirement like, "how many posts with category option 'c'"?
2nd one is easy to do the statistic, but the 1st one...
category_option must have category id to make a conjunction table with opton_post otherwise there is no mean to create that 2nd table structure.
two thing you can achieve here with that structure.
1) make a one to one relationship with post to category. (this mean you can add more categories in future if its needed)
2) in this structure null values automatically avoided. this mean no more handling null values in table or in sql queries.
hope this helps.

MySQL, per found record join a different parent table

I have the following parent <-> child datamodel:
(almost every line is a table, indented means child-of)
consumerGoods
food
meat
item
fruit
item
vegetable
item
The child-items of meat, fruit and vegetables are in the same table (named items) because they have identical attributes. In the items table I have fields that describes the parent and the parentId.
So an item record could be:
id:1
parentType:meat
parentId:4
price:3.25
expDate:2009-12-31
description:bacon
I'm now building a full text MySQL search for the contents of the description field in "items", but I also want each result to have the information of its parent table, so a "bacon-item" has the data that's in its parent record. I also want each returned result to have data that is in the parent food record and the parent consumerGoods record.
I've got the following query now, but I don't know how to join based on the value of a field in a record, or if that's even possible.
SELECT
*
FROM
item
WHERE MATCH
(description
AGAINST
('searchKey')
One way to do this is is to do multiple queries for each matching "item" record, but if I had a lot of results that would be a lot of queries and would also slow down any filtering I'd want to do for facet-based searching. Another option is to make a new table that contains all the parent item info for each item record and search through that, but then I'd have to constantly update that table if I add item records, which is redundant and quite some work.
I'd like to hear it if I'm thinking in the right direction, or if I'm totally misguided. Any suggestions welcome.
As a general rule of thumb your database structure should contain data, but should not itself be data. A sign that you're breaking this is when you feel that you have to join to a different table based on the data you're reading from some other table. At that point you need to back up and consider your overall data model because odds are very good that you're doing something not quite right.
You could join against a subquery containing the union of all parent types:
select *
from item
left join (
select 'meat' as type, Redness, '' as Ripeness from meat
union all
select 'fruit' as type, -1 as Redness, Ripeness from fruit
union all
select 'vegetable' as type, -1 as Redness, Ripeness from vegetable
) parent on parent.type = item.parentType
But if you can, redesign the database. Instead of the complex model, change it to one table of Items and one table of Categories. The categories should contain one row for meat, one for fruit, and one for vegetables.
Since your example is contrived, it's difficult to know what the actual information requirements are in your case. Damir's diagram shows you the correct way to model PKs and FKs when you have a super-type sub-type relationships.
This situation is one case of a pattern called "generalization-specialization". Almost any treatment of object modeling will deal with generalization-specialization, although it may use different terminology. However, if you want to find articles that help you build a relational database that uses specialization-generalization, search for "generalization specialization relational modeling".
The best of the articles will start by teaching you the same concept that Damir's response illustrated for you. From there, you will learn how to create queries and views that can search for either all kinds of items, or for particular kinds of items, if you know what you are searching for.
A sample view follows:
create view FruitItems as
select
c.ConsumerGoodsID,
Price,
Description,
ConsumerGoodType,
ExpiryDate,
FoodType,
IsTropic
from
ConsumerGoods c
INNER JOIN Food f on f.ConsumerGoodsID = c.ConsumerGoodsID
INNER JOIN Fruit fr on fr.ConsumerGoodsID = c.ConsumerGoodsID
Similarly, you could create views for VegetableItems, MeatItems, and HouseSupplyItems, and even one large view, namely Items, that's the union of each of the specialized views.
In the Items view IsTropic would be true for all tropical fruits, false for all non tropical fruits, and null for Meats, Vegetables, and HouseSupplies. I'm not going to show you the entire Item view for a contrived case, but you get the idea. Especially if you read the best of the articles on relational modeling of this pattern.
The Items view might be a little slow, but it could come in handy when you really don't know any better way to search. And if you search for Istropic = True, you'll automatically exclude all the Meats, Vegetables, and HouseSupplies.
As #Andomar suggested, the design is a bit off; having "multiple parent tables" does not map to DB foreign keys concept. Here is one possible suggestion. This one uses two levels of super-type/subtype relationships. Super-type table contains columns specific to all subtypes (categories), while subtype tables contain columns specific only to the category.