Why is this query duplicating results? - mysql

I'm not very experienced when it comes to joining tables so this may be the result of the way I'm joining them. I don't quite understand why this query is duplicating results. For instance this should only return 3 results because I only have 3 rows for that specific job and revision, but its returning 6, the duplicates are exactly the same as the first 3.
SELECT
checklist_component_stock.id,
checklist_component_stock.job_num,
checklist_revision.user_id,
checklist_component_stock.revision,
checklist_category.name as category,
checklist_revision.revision_num as revision_num,
checklist_revision.category as rev_category,
checklist_revision.per_workorder_number as per_wo_num,
checklist_component_stock.wo_num_and_date,
checklist_component_stock.posted_date,
checklist_component_stock.comp_name_and_number,
checklist_component_stock.finish_sizes,
checklist_component_stock.material,
checklist_component_stock.total_num_pieces,
checklist_component_stock.workorder_num_one,
checklist_component_stock.notes_one,
checklist_component_stock.signoff_user_one,
checklist_component_stock.workorder_num_two,
checklist_component_stock.notes_two,
checklist_component_stock.signoff_user_two,
checklist_component_stock.workorder_num_three,
checklist_component_stock.notes_three,
checklist_component_stock.signoff_user_three
FROM checklist_component_stock
LEFT JOIN checklist_category ON checklist_component_stock.category
LEFT JOIN checklist_revision ON checklist_component_stock.revision = checklist_revision.revision_num
WHERE checklist_component_stock.job_num = 1000 AND revision = 1;
Tables structure:
checklist_category
checklist_revision
checklist_component_stock

The line
LEFT JOIN checklist_category ON checklist_component_stock.category
was certainly supposed to be something like
LEFT JOIN checklist_category ON checklist_component_stock.category = checklist_category.category
Most other dbms would have reported a syntax error, but MySQL treats checklist_component_stock.category as a boolean. For MySQL a boolean is a number, which is 0 for FALSE and != 0 for TRUE. So every checklist_component_stock with category != 0 is being connected to all records in checklist_category.

First check your query as join is missing in your first left join. Also If you just want to get unique rows from your query then use of distinct just after select...

As well as fixing Thorsten Kettner's suggestion, my foreign keys for the revisions was off. I was referencing the revision in checklist_component_stock.revision to checklist_revision.revision_num when instead I should have referenced it to checklist_revision.id.

Related

How to return row with diffrent value if "where" has not been met in MySQL

I have problem with receiving rows if id from one table dont match second one.
If zamowienia.id_telefon is null or dont match i dont recive whole row.
I want to instead get column crm2018.telefon.numer with "0" or null value. Please help :)
I tried something like that but its obvious syntax eror:
SELECT
crm2018.zamowienia.*,
crm2018.telefon.numer
FROM
crm2018.zamowienia
JOIN crm2018.telefon
WHERE
if (zamowienia.id_telfon != "0") zamowienia.id_telefon = telefon.id_telefon else crm2018.telefon.numer as "0"
Here's working code but with missing rows.
SELECT
crm2018.zamowienia.*,
crm2018.telefon.numer
FROM
crm2018.zamowienia
JOIN crm2018.telefon
WHERE
zamowienia.id_telefon = telefon.id_telefon
Just use LEFT JOIN instead of (INNER) JOIN.
Accordingly, you need to move the join condition from the WHERE clause to the ON clause of the join, to avoid filtering out unmatched records. Please note that as it is, your query has a JOIN without ON clause : this is a syntax error in all SQL dialects.
Finally, I would recommend using table aliases in the query : this makes it easier to read and to maintain.
SELECT
z.*,
t.numer
FROM
crm2018.zamowienia AS z
LEFT JOIN crm2018.telefon AS t
ON z.id_telefon = t.id_telefon
When no record is available in crm2018.telefon for the given crm2018.zamowienia, the record will still be displayed, with all columns coming from crm2018.telefon showing NULL values.
If needed, you can turn NULL values to 0 with the COALESCE() function, like :
COALESCE(t.numer, 0)

SQL JOIN gives double results

My database and SQL:
http://sqlfiddle.com/#!9/ebddb/1/0
Problem:
It's returning duplicates, with the wrong data in the name-column, when there are less than 7 records in the notchtype-table
My Question:
Why does it return duplicates and how to prevent it?
Expected result:
This fiddle shows the expected result: http://sqlfiddle.com/#!9/22660/1
In this result the only thing more added than in my actual database and SQL are 2 records in the notchtype-table
So the id, notchid and number columns should be unique in the returned rows.
The screenshot in the answer of Piyush Gupta is showing the right expected result. The same query on SQL fiddle and locally on MariaDB version 10.1.9 are returning something different
Notes:
I found out that when there at least 7 records in the notchtype table, there are suddenly no duplicates anymore and the problem is 'solved'.
The null values should indeed be null.
The size-column is actually returning the right values, although the LEFT JOIN is more or less the same
The ID's in notches.notchdescr 'connects' with the ID's in notchtype.notchtypeid column and is returned as the name column in the fiddle
The ID's in notches.notchsize 'connects' with the ID's in notchsize.notchsizeid column and is returned as the size column in the fiddle
Not working:
INNER JOIN, don't know why
DISTINCT, because the name-columns have different values, so there not exact duplicates
GROUP BY, because it returns all the same values in the name-column
Update on answer/comments from Piyush Gupta
Query executed on MySQL 5.7:
SELECT
notches.id,
notches.notchid,
notches.number,
notches.xcoord,
notches.ycoord,
notches.mapid,
notches.location,
notches.date,
notches.price,
notches.invoiced,
notchsize.size AS notchsize,
notchtype.name AS notchdescr
FROM
notches
LEFT JOIN
notchtype ON
notches.notchdescr = notchtype.notchtypeid
LEFT JOIN
notchsize ON
notches.notchsize = notchsize.notchsizeid
WHERE
notches.del = 0
AND
notches.projectid = '2016032411364363055'
GROUP BY notches.id, notches.notchid, notches.number
ORDER BY notches.number ASC
Result:
SOLVED!
LEFT JOIN on VARCHAR = BIGINT field causes the strange returned values. See answer and comments of Piyush Gupta
You missed the GROUP BY in your query for Aggregate the data. so your query will be,
SELECT
notches.id,
notches.notchid,
notches.number,
notches.xcoord,
notches.ycoord,
notches.mapid,
notches.location,
notches.descr,
notches.date,
notches.price,
notches.invoiced,
notchtype.name AS notchdescr,
notchsize.size AS notchsize
FROM
notches
LEFT JOIN
notchtype ON
notches.notchdescr = notchtype.notchtypeid
LEFT JOIN
notchsize ON
notches.notchsize = notchsize.notchsizeid
WHERE
notches.del = 0
AND
notches.projectid = '2016032411364363055'
GROUP BY notches.id,
notches.notchid,
notches.number
ORDER BY notches.number ASC;
Output: ONLINE DEMO HERE
NOTE: I Imported your data structure locally and I'm getting same output which is your expectation but In SQLFiddle, notchtype.name AS notchdescr column is not executing in SQLFiddle that is showing only name column of notchtype table. So you can use above query and check locally in your database. I hope you will get require output.
Screenshot(Using MySQL Workbench)
Update 1: It was strange error. I reviewed database structure and found solution that was data type issue only. You were joining bigint and varchar data type so you need to correct data type. Here I'm changing data type bigint to varchar for notchsizeid in notchsize table and notchtypeid in notchtype table. Finally your Expected output is coming. You can SEE OUTPUT HERE.
You can do by using group by . But you need to tell your logic for this.
SELECT
notches.id,
notches.notchid,
notches.number,
notches.xcoord,
notches.ycoord,
notches.mapid,
notches.location,
notches.descr,
notches.date,
notches.price,
notches.invoiced,
notchtype.name AS notchdescr,
notchsize.size AS notchsize
FROM
notches
LEFT JOIN
notchtype ON
notches.notchdescr = notchtype.notchtypeid
LEFT JOIN
notchsize ON
notches.notchsize = notchsize.notchsizeid
WHERE
notches.del = 0
AND
notches.projectid = '2016032411364363055'
group by id
ORDER BY notches.number ASC

SQL Query seems not to affect the same number of rows, Adding a count statement

I have made a query that looks like this
Query 1.
SELECT zlec_status.nazwa AS Status,
piorytet.nazwa AS Priorytet,
Concat(koord.imie, ' ', koord.nazwisko) AS `Koordynator`,
Concat(zlec_adresy.miasto, ' - ', zlec_adresy.ulica, ' ',
zlec_adresy.oddzial)
AS `adres`,
zlec_z_dnia,zlec_id,
zlec_nr,
zlec_do,
zlec_ogran,
awizacje,
awizacja_na_dzien,
termin_zamkniecia,
tresc,
uwagi
FROM zlec
INNER JOIN koord
ON zlec.koord = koord.id
INNER JOIN zlec_adresy
ON zlec.zlec_addres = zlec_adresy.id
INNER JOIN piorytet
ON zlec.priorytet = piorytet.id
INNER JOIN zlec_status
ON zlec.status_zlecenia = zlec_status.id
And the following one which is a ordinary one
Query 2.
SELECT * FROM zlec;
The thing is the first one returns ( affects by executing ) 48 rows where the second query returns 103 rows. What could be the possible cause of this?
I will also show you my dumb of the sql in case you would like to make a run on your own http://pastebin.com/cMPAtxCU .
Subquestion - quite no point starting of with a new question for that because its also connected with the row count affect.
Besides I was wondering how can I get into the first query a count(*) to get the affected rows - it has to be done in sql I cannot use php code for that, probably it would be good to use a limit 1 for the count.
With INNER JOIN, if one of your other tables, koord, zlec_adresy, piorytet and zlec_status is missing a record corresponding to a record in zlec, that record in zlec will not be in the result set. If you want every record in zlec to appear, you have to use LEFT JOIN. Check out:
http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
For a pretty good explanation.
With your additional inner joins rows might be eliminated. Have you tried adding the inner joins to your "Select * FROM zlec;"?

MySQL: Subquery returns more than 1 row

I know this has been asked plenty times before, but I cant find an answer that is close to mine.
I have the following query:
SELECT c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName, c.cases_timestamp, o.organisation_name
FROM db_cases c, db_custinfo ci, db_organisation o
WHERE c.userInfo_ID = ci.userinfo_ID AND c.cases_status = '2'
AND organisation_name = (
SELECT organisation_name
FROM db_sites s, db_cases c
WHERE organisation_ID = '111'
)
AND s.sites_site_ID = c.sites_site_ID)
What I am trying to do is is get the cases, where the sites_site_ID which is defined in the cases, also appears in the db_sites sites table alongside its organisation_ID which I want to filter by as defined by "organisation_ID = '111'" but I am getting the response from MySQL as stated in the question.
I hope this makes sense, and I would appreciate any help on this one.
Thanks.
As the error states your subquery returns more then one row which it cannot do in this situation. If this is not expect results you really should investigate why this occurs. But if you know this will happen and want only the first result use LIMIT 1 to limit the results to one row.
SELECT organisation_name
FROM db_sites s, db_cases c
WHERE organisation_ID = '111'
LIMIT 1
Well the problem is, obviously, that your subquery returns more than one row which is invalid when using it as a scalar subquery such as with the = operator in the WHERE clause.
Instead you could do an inner join on the subquery which would filter your results to only rows that matched the ON clause. This will get you all rows that match, even if there is more than one returned in the subquery.
UPDATE:
You're likely getting more than one row from your subquery because you're doing a cross join on the db_sites and db_cases table. You're using the old-style join syntax and then not qualifying any predicate to join the tables on in the WHERE clause. Using this old style of joining tables is not recommended for this very reason. It would be better if you explicitly stated what kind of join it was and how the tables should be joined.
Good pages on joins:
http://dev.mysql.com/doc/refman/5.0/en/join.html (for the right syntax)
http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html (for the differences between the types of joins)
I was battling this for an hour, and overcomplicated it completely. Sometimes a quick break and writing it out on an online forum can solve it for you ;)
Here is the query as it should be.
SELECT c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName, c.cases_timestamp, c.sites_site_ID
FROM db_cases c, db_custinfo ci, db_sites s
WHERE c.userInfo_ID = ci.userinfo_ID AND c.cases_status = '2' AND (s.organisation_ID = '111' AND s.sites_site_ID = c.sites_site_ID)
Let me re-write what you have post:
SELECT
c.cases_ID, c.cases_status, c.cases_title, ci.custinfo_FName, ci.custinfo_LName,
c.cases_timestamp, c.sites_site_ID
FROM
db_cases c
JOIN
db_custinfo ci ON c.userInfo_ID = ci.userinfo_ID and c.cases_status = '2'
JOIN
db_sites s ON s.sites_site_ID = c.sites_site_ID and s.organization_ID = 111

Correct MySQL JOIN format to avoid nested SELECT

I have two separate SELECT statements:
SELECT VCe.VId FROM `VCe` WHERE `YId` = 9007 AND `MaId` =76 AND `MoId` = 2851
SELECT r_pts.p_id FROM r_pts WHERE r_pts.v_id IN (57202, 57203, 69597, 82261, 82260, 69596, 69595, 82259)
When they are run separately they both complete in under .05sec however when I nest the first one within the second, it dramatically increases to 3.3sec.
I would like to do a join so that I can get the output from the second SELECT using the first select as the result set for the IN() but I cannot figure out how to include WHERE conditions in a JOIN.
Edit: Also what is the correct syntax to do a join as I am requesting?
Thanks for your help, its appreciated!
Equivalent to MattMcKnight's query whilst illustrating "how to include WHERE conditions in a JOIN":
SELECT r.p_id
FROM r_pts r
INNER JOIN VCe v
ON v.VId = r.v_id
AND
v.YId = 9007
AND
v.MaId = 76
AND
v.MoId = 2851
SELECT r_pts.p_id FROM r_pts, 'VCe' WHERE r_pts.v_id = VCe.VId AND VCe.YId = 9007 AND VCe.MaId =76 AND VCe.MoId = 2851
The basic goal of a join is to describe how the two tables relate. I inferred from your example that the v_id column in the r_pts table was a foreign key pointing to the VId primary key in the VCe table. When you add a term in the query (such as "r_pts.v_id = VCe.VId") that has a field from each table you wish to join, that tells the database how to match up the rows between the tables to make "virtual rows" that contain the columns from both tables. Your other query terms limit which rows are included in the result set.