SQL Query Help on 3 Tables with a Many to Many relationship - mysql

I had an issue joining multiple tables to retrieve the data I needed. In order to accomplish the proper results I had to first create a view (shown below) called: vwinvgrossrev :
SELECT dbo.inv_item.inv_num, dbo.inv_item.co_line,
dbo.inv_hdr.co_num, dbo.inv_hdr.inv_date, dbo.inv_item.qty_invoiced,
dbo.inv_item.price
FROM dbo.inv_item INNER JOIN
dbo.inv_hdr ON dbo.inv_item.inv_num = dbo.inv_hdr.inv_num
and then I had to join the view on my final table in order to create a proper summation of the values that I wanted
select sum(vwinvgrossrev.qty_invoiced*vwinvgrossrev.price)
from vwinvgrossrev,coitem
WHERE vwinvgrossrev.co_num=coitem.co_num
AND coitem.Uf_Erne='Y'
AND vwinvgrossrev.co_line=coitem.co_line
AND DATEPART(mm,vwinvgrossrev.inv_date) = DATEPART(mm,Getdate())
AND YEAR(vwinvgrossrev.inv_date) = YEAR(Getdate())
My question is this. Is there anyway to do this in a single query. The problem is all 3 tables have a many to many relationship with one another and always returns the wrong value when joining all 3 tables.

If your current query (using the view) gives you what you are looking for then I believe that this query will give you the same thing in a single query:
SELECT sum(inv_item.qty_invoiced*inv_item.price)
FROM inv_item
JOIN inv_hdr ON dbo.inv_item.inv_num = dbo.inv_hdr.inv_num
JOIN coitem ON (inv_hdr.co_num=coitem.co_num
AND inv_item.co_line=coitem.co_line)
WHERE coitem.Uf_Erne='Y'
AND vwinvgrossrev.co_line=coitem.co_line
AND DATEPART(mm,inv_hdr.inv_date) = DATEPART(mm,Getdate())
AND YEAR(inv_hdr.inv_date) = YEAR(Getdate())
However, I'll be surprised if that is what you are looking for.
I am assuming that you don't actually have a many-to-many between all 3. I am assuming that inv_hdr has a unique inv_num and inv_item has many of those. Similarly I am assuming that co_num is unique within inv_hdr but has multiple occurrences within coitem. These are not many-to-many but rather 1-to-many relationships. Since SELECT multiplies rows I think you are going to be summing way more than you want.
Why do you want to include coitem at all if you are just interested in inv_item.qty_invoiced and inv_item.price? Is it just to limit on the Uf_Erne column? Is coitem always going to have either 1 or 0 records for that co_num and co_line with Uf_Erne='Y'?
In sum, I've reproduced your query in a single query without a view, but I think you may need to think through whether this is really what you want.

You need to refine your database schema to normalise out the many-to-many relationships. That is a given and is standard practice regardless of your current problem. The fact that it will simplify your current problem is the reason why. There are many tutorials/blog/etc out there to show you how to do this with join tables so I am not going into it here.

Related

Subquery or join to get one string from the same two tables multiple times

Related to Join vs. sub-query but a different type of situation, and just trying to understand how this works.
I had to make a view where I get a bunch of employee codes from one table, and I have to get their names from a different table - the same two tables every time. I arranged my query like this:
SELECT
(SELECT name from emptable where empcod = code1) as emp1, code1,
(SELECT name from emptable where empcod = code2) as emp2, code2,
[repeat 6 times]
FROM codetable
It is more complicated than this, and more tables are joined, but this is the element I want to ask about. My boss says joining like so is better:
SELECT e1.name, c.code1, e2.name, c.code2, e3.name, code3 [etc]
FROM codetable c
INNER JOIN emptable e1 ON e1.empcod = c.code1
INNER JOIN emptable e2 ON e2.empcod = c.code2
INNER JOIN emptable e3 ON e3.empcod = c.code3
My reasoning, aside from not having to go search in the joins which table gets whose name and why, is the way I understand the join goes like this:
Take whole table A
Take whole table B
Combine all the data from both tables according to the 'ON' section of the join
select one single string from this complete combination of two whole tables from which I need no other data
I think it's obvious that this seems like it would take up a lot of resources. I understand the subquery as
Get one datum from table A (the employee code)
Match this one datum to every record from table B until you find a match
As soon as you get a match, bring back this one single datum from this other table (the employee's name)
Understanding that in the table of employees, the employee code is a primary key and cannot be duplicated, so every subquery can only ever give me one single string back.
It seems to me that comparing ONE number from one table to ONE number from another table and retrieving ONE string related to that number would be less resource-intensive than matching ALL of the data in two whole tables together in order to get this one string. But I figure I don't know what these databases are doing behind the scenes, and a lot of people seem to prefer joins. Can anyone explain this to me, if I'm understanding it wrong? The other posts I find here of similar situations tend to want more information from more tables, I'm not immediately finding anything about matching the same two tables six or seven times to retrieve one single string for every configuration.
Thanks in advance.
So as ScaisEdge explained, a join only gets executed once - and thus only spends time and resources once - no matter how many rows you have, whereas each of the six subselects get executed once for every row. If you have 100 rows, you're executing six joins once or you're executing 6 subselects 100 times.
It makes sense that this would be more resource-intensive, and I did not explain clearly enough that my case involves only one row at a time - in which case I guess the difference would be negligible anyway.

MySQL - Join View and Table

I have a view called "xml_links" which is in the following format
model_number fk_link sd_link
10R46 www.fk.com/10R46 www.sd.com/10R46
10R47 www.fk.com/10R47 www.sd.com/10R47
And a table called "prohub"
page_url fk_price sd_price
www.fk.com/10R46 $155
www.sd.com/10R46 $161
www.fk.com/10R47 $117
www.sd.com/10R47 $146
I'm trying to join them using the following query and all I get is a blank table.
select
xml_links.model_number,
prohub.fk_price,
prohub.sd_price
from
xml_links, prohub
where
xml_links.fk_link=prohub.page_url
and
xml_links.sd_link=prohub.page_url
I'm looking for the following result:
model_number fk_price sd_price
10R46 $155 $161
10R47 $117 $146
Thanks for your help
They query that you are looking for
SELECT model_number,
(SELECT flipkart_price FROM pro_hub WHERE page_url=flipkart_link and flipkart_price is not null),
(SELECT snapdeal_price FROM pro_hub WHERE page_url=snapdeal_link and snapdeal_price is not null)
FROM xml_links
But this is really a patchwork solution for a database that neesd to be normalized
The solution that you are really looking for
Is a redesign of your tables.
In a proper RDBMS one does not have repetitive data. In your database values like 'www.fk.com/10R46' repeat not in just one table (which is bad enough but in two tables).
Secondly you are storing values in columns rather than in rows. The solution I have given you will work very well as long as you have only two vendors but what happens when you add a third vendor? YOu need to add a third column to both of your tables. That might takes hours if you have millions of records and during that time the site will be unresponsive.
what about this, is this what you needed?
select
model_number
, sum(fk_price) as fk_price
, sum(sd_price) as sd_price
from xml_links xml
INNER JOIN prohub pro
on right(pro.page_url, 5) = xml.model_number
GROUP BY model_number;

MySQL statement to read data from one table with checks on another table

I have these two tables:
Achievement:
Achieves:
Question:
I want to retrieve rows from table Achievement. But, I do not want all the rows, I want the rows that a specific Steam ID has acquired. Let's take STEAM_0:0:46481449 for example, I want to check first the list of IDs that STEAM_0:0:46481449 has acquired (4th column in Achieves table states whether achievement is acquired or not) and then read only those achievements.
I hope that made sense, if not let me know so I can explain a little better.
I know how to do this with two MySQL statements, but can this be done with a single MySQL statement? That would be awesome if so please tell me :D
EDIT: I will add the two queries below
SELECT * FROM Achieves WHERE Achieves.SteamID = 'STEAM_0:0:46481449' AND Achieves.Acquired = 1;
Then after that I do the following query
SELECT * FROM Achievement;
And then through PHP I would check the IDs that I should take and output those. That's why I wanted to get the same result in 1 query since it's more readable and easier.
In sql left join, applying conditions on second table will filter the result when join conditions doesn't matter:
Select * from achievement
left join achieves on (achievement.id=achieves.id)
where achieves.acquired=1 and achieves.SteamID = 'STEAM_0:0:46481449'
Besides,I suggest not using ID in the achieves table as the shared key between two tables. Name it something else.
I don't think a left join makes sense here. There is no case where you don't want to see the Achievement table.
Something like this
SELECT *
FROM Achieves A
JOIN Achievement B on A.ID = B.ID
WHERE A.SteamID = 'STEAM_0:0:46481449'
AND A.Acquired = 1;

Joining 5 tables - 1 master plus 4 with multiple rows to the master but master data is duplicated

I am working in mysql with queries, but I am new to this. I am joining 5 tables where each table has an identifier and one table is the master. Each related table may have more than one associated record to the master table. I am attempting to join these tables but I can't seem to get rid of the duplicated data.
I want all of the related records to be displayed, but I don't want the data in the master table to display for all results in the related tables. I have tried so many different methods but nothing has worked. Currently I have 4 queries that work for the separate tables, but I have not successfully joined them to have the results display the multiple records in the related table but just one record from the master table.
Here are my individual queries that work:
SELECT
GovernmaxAdditionsExtract.AdditionDescr,
GovernmaxAdditionsExtract.BaseArea,
GovernmaxAdditionsExtract.Value
FROM
GovernmaxExtract
INNER JOIN GovernmaxAdditionsExtract
ON GovernmaxExtract.mpropertyNumber = GovernmaxAdditionsExtract.PropertyNumber
WHERE (((GovernmaxExtract.mpropertyNumber)="xxx-xxx-xx-xxx"));
SELECT
GovernmaxExtract.mpropertyNumber,
GovernmaxDwellingExtract.CardNumber,
GovernmaxDwellingExtract.MainBuildingType,
GovernmaxDwellingExtract.BaseArea
FROM
GovernmaxExtract INNER JOIN
GovernmaxDwellingExtract ON GovernmaxExtract.mpropertyNumber = GovernmaxDwellingExtract.PropertyNumber
WHERE (((GovernmaxExtract.mpropertyNumber)="xxx-xxx-xx-xxx"));
Using these sub queries, I tried to put together 2 of the tables, but now I am getting all records back and it is not reading my input parameter:
SELECT GE.mpropertynumber
FROM
GovernmaxExtract AS GE,
(SELECT
GovernmaxAdditionsExtract.AdditionDescr,
GovernmaxAdditionsExtract.BaseArea,
GovernmaxAdditionsExtract.Value
FROM GovernmaxExtract INNER JOIN
GovernmaxAdditionsExtract ON
governmaxextract.mpropertyNumber = GovernmaxAdditionsExtract.PropertyNumber) AS AE
WHERE GE.mpropertynumber = 'xxx-xxx-xx-xxx'
I tried nested queries, lots of different joins, and I am just not able to wrap my head around this. I am pretty sure I want to do a nested query since I want the main data from the Governmax table to display once with the main data and all records with all info for the associated tables. Maybe I am going about it all wrong.
Our original code was:
SELECT
ge.*,
gde.*,
gfe.*,
gae.*,
goie.*
FROM governmaxextract AS ge
LEFT JOIN governmaxdwellingextract AS gde
ON ge.mpropertyNumber = gde.PropertyNumber
LEFT JOIN governmaxfeaturesextract AS gfe
ON gde.PropertyNumber = gfe.PropertyNumber
LEFT JOIN governmaxadditionsextract AS gae
ON gde.PropertyNumber = gae.PropertyNumber
RIGHT JOIN governmaxotherimprovementsextract AS goie
ON gde.PropertyNumber = goie.PropertyNumber
WHERE ge.mpropertyNumber = '$codeword'
ORDER BY goie.CardNumber
But this gives multiple rows from the master table for each record in the associated tables. I thought about concatenate, but I need the data from the associated tables to be displayed individually. Not sure what to try next. Any help is much appreciated.
Sorry, and there is no way to do that like you want. JOIN's can't do that.
I suggest to keep solution with separate queries.
Btw - You could play with UNION operator,
http://en.wikipedia.org/wiki/Union_(SQL)#UNION_operator
P.s.
You could extract main data separately, then extract data from related tables at once using UNION. With UNIOM it will give one result row per each row in related table.
In order to join an two of the Detail tables together without generating duplicate rows, you will have to perform the following operation on each one:
Group on the foreign key to the Master table, and aggregate all other columns being projected onto the join.
Numeric columns are commonly aggregated with SUM(), COUNT(), MAX(), and MIN(). MAX() and MIN() are also applicable to character data. A PIVOT operation is also sometimes useful as an aggregation operator for this type of circumstance.
Once you have two of the Detail tables grouped and aggregated in this way, they will join without duplicates. Additional Detail tables can be added to the join by first grouping and aggregating them also, in the same fashion.

MySQL JOIN based on dynamic LIKE statement between multiple tables

I have a table called faq. This table consists from fields faq_id,faq_subject.
I have another table called article which consists of article_id,ticket_id,a_body and which stores articles in a specific ticket. Naturally there is also a table "ticket" with fields ticket_id,ticket_number.
I want to retrieve a result table in format:
ticket_number,faq_id,faq_subject.
In order to do this I need to search for faq_id in the article.a_body field using %LIKE% statement.
My question is, how can I do this dynamically such that I return with SQL one result table, which is in format ticket_number,faq_id,faq_subject.
I tried multiple configurations of UNION ALL, LEFT JOIN, LEFT OUTER JOIN statements, but they all return either too many rows, or have different problems.
Is this even possible with MySQL, and is it possible to write an SQL statement which includes #variables and can take care of this?
First off, that kind of a design is problematic. You have certain data embedded within another column, which is going to cause logic as well as performance problems (since you can't index the a_body in such a way that it will help the JOIN). If this is a one-time thing then that's one issue, but otherwise you're going to have problems with this design.
Second, consider this example: You're searching for faq_id #123. You have an article that includes faq_id 4123. You're going to end up with a false match there. You can embed the faq_id values in the text with some sort of mark-up (for example, [faq_id:123]), but at that point you might as well be saving them off in another table as well.
The following query should work (I think that MySQL supports CAST, if not then you might need to adjust that).
SELECT
T.ticket_number,
F.faq_id,
F.faq_subject
FROM
Articles A
INNER JOIN FAQs F ON
A.a_body LIKE CONCAT('%', F.faq_id, '%')
INNER JOIN Tickets T ON
T.ticket_id = A.ticket_id
EDIT: Corrected to use CONCAT
SELECT DISTINCT t.ticket_number, f.faq_id, f.faq_subject
FROM faq.f
INNER JOIN article a ON (a.a_body RLIKE CONCAT('faq_id: ',faq_id))
INNER JOIN ticket t ON (t.ticket_id = a.ticket_id)
WHERE somecriteria