Finding differences in queries using two criteria - sql

I'm trying to find a way to find a way to compare two queries that use a combine sent of criteria. In this case we have Prefixes (Two letter code like DA) and Pack number 1234567. In the query I've created a field that combines these two things so it appears 1234567DA this is done with each of the queries from the separate tables they are pulled from. The idea is that if this is in one table and not the other it would show up as "False". I tried to use an Unmatched query but that doesn't seem to work. What I have currently is as follows:
SELECT
[1LagoTest].Prefix,
[1BigPicPackPref].BigPicPP,
IIf([BigPicPP]=[LagoPP],"True","False") AS Compare,
[1LagoTest].RETAIL,
[1LagoTest].MEDIA
FROM 1LagoTest
LEFT JOIN 1BigPicPackPref
ON [1LagoTest].[Prefix] = [1BigPicPackPref].[BigPicPP]
WHERE (((IIf([BigPicPP]=[LagoPP],"True","False")) Like "False")
AND (([1LagoTest].MEDIA) Not Like "*2019 FL*"))
ORDER BY [1LagoTest].RETAIL;
Right now it will show whats missing from LagoPP but doesn't give me anything from missing packs in BigPicPP. Any help in the right direction would be greatly appreciated.
Thanks!!

This gets a little tricky in Access without FULL OUTER JOIN, but the general idea to is replicate a FULL OUTER JOIN using UNION ALL, then filter from that.
Something like this:
SELECT I.Prefix,
I.BigPicPP,
I.Compare,
I.Retail,
I.Media
FROM (SELECT L.Prefix,
B.BigPicPP,
IIf([BigPicPP]=[LagoPP],"True","False") as Compare,
L.Retail,
L.Media
FROM 1LagoTest L
JOIN 1BigPicPackPref B ON L.Prefix = B.BigPicPP
WHERE L.Media NOT LIKE "*2019 FL*"
UNION ALL
SELECT L.Prefix,
B.BigPicPP,
"False", --Missing records from 1BigPicPackPref
L.Retail,
L.Media
FROM 1LagoTest L
LEFT JOIN 1BigPicPackPref B ON L.Prefix = B.BigPicPP
AND L.Media NOT LIKE "*2019 FL*"
WHERE B.Prefix IS NULL
UNION ALL
SELECT B.Prefix,
B.BigPicPP,
"False", --Missing records from 1LagoTest
L.Retail,
L.Media
FROM 1LagoTest L
RIGHT JOIN 1BigPicPackPref B ON L.Prefix = B.BigPicPP
AND L.Media NOT LIKE "*2019 FL*"
WHERE L.Prefix IS NULL
) AS I
You only need IFF in the first part of the union because in the second two parts one side will always be NULL, so we know the compare will always fail and be False.
You shouldn't need this part of your current WHERE clause at all (((IIf([BigPicPP]=[LagoPP],"True","False")) Like "False"). But if you only want to see False records, just add WHERE I.Compare = "False" to the bottom of the outer select.

The reason the "Unmatched" query (assuming through the Wizard) does not work, is because you are attempting to see the values of two separate tables / queries that do not match either table / query. This is not how the "Unmatched" works. All that will give you is a single table / query that does not match another single table / query.
This can most likely be done any number of ways, but this would probably get you where you want to be (or close to it):
SELECT
a.Prefix,
b.BigPicPP,
IIf([BigPicPP]=[LagoPP],"True","False") AS Compare,
a.RETAIL,
a.MEDIA
FROM [1LagoTest] a
LEFT JOIN [1BigPicPackPref] b ON a.Prefix = b.BigPicPP
WHERE a.MEDIA Not Like "*2019 FL*"
AND b.BigPicPP IS NULL
ORDER BY a.RETAIL
UNION
SELECT
a.Prefix,
b.BigPicPP,
IIf([BigPicPP]=[LagoPP],"True","False") AS Compare,
a.RETAIL,
a.MEDIA
FROM [1LagoTest] a
RIGHT JOIN [1BigPicPackPref] b ON a.Prefix = b.BigPicPP
WHERE a.MEDIA Not Like "*2019 FL*"
AND a.Prefix IS NULL
ORDER BY a.RETAIL
NOTE: Depending on the data structure, the ORDER BY may cause some issues.

So the way I got this to finally work was to build two separate queries. One looking at what was missing from Lago and One that was looking at what was missing from BigPic. It was the only way I could get it to give me both sets of missing data. If I can find a better way to do it through one query I will report back as I'm still gonna play around with it.

Related

Access SQL query without duplicate results

I made a query and wanted to not have any duplicates but i got some times 3 duplicates and when i used DISTINCT or DISTINCTROW i got only 2 duplicates.
SELECT f.flight_code,
f.status,
a.airport_name,
a1.airport_name,
f.departing_date+f.departing_time AS SupposedDepartingTime,
f.landing_date+f.landing_time AS SupposedLandingTime,
de.actual_takeoff_date+de.actual_takeoff_time AS ActualDepartingTime,
SupposedLandingTime+(ActualDepartingTime-SupposedDepartingTime) AS ActualLandingTime
FROM
(((Flights AS f
LEFT JOIN Aireports AS a
ON a.airport_code = f.depart_ap)
LEFT JOIN Aireports AS a1
ON f.target_ap = a1.airport_code)
LEFT JOIN Irregular_Events AS ie
ON f.flight_code = ie.flight_code)
LEFT JOIN Delay_Event AS de
ON ie.IE_code = de.delay_code;
had to use LEFT JOIN because when i used INNER JOIN i missed some of the things i wanted to show because i wanted to see all the flights and not only the flights that got delayed or canceled.
This is the results when i used INNER JOIN, you can see only the flights that have the status "ביטול" or "עיכוב" and that is not what i wanted.
[the results with LEFT JOIN][2]
[2]: https://i.stack.imgur.com/cgE2G.png
and when i used DISTINCT where you see the rows with the NUMBER 6 on the first column it appear only two times
IMPORTANT!
I just checked my query and all the tables i use there and i saw my problem but dont know how to fix it!
in the table Irregular_Events i have more the one event for flights 3,6 and 8 and that is why when i use LEFT JOIN i see more even thou i use distinct, please give me some help!
Not entirely sure without seeing the table structure, but this might work:
SELECT f.flight_code,
f.status,
a.airport_name,
a1.airport_name,
f.departing_date+f.departing_time AS SupposedDepartingTime,
f.landing_date+f.landing_time AS SupposedLandingTime,
de.actual_takeoff_date+de.actual_takeoff_time AS ActualDepartingTime,
SupposedLandingTime+(ActualDepartingTime-SupposedDepartingTime) AS ActualLandingTime
FROM
((Flights AS f
LEFT JOIN Aireports AS a
ON a.airport_code = f.depart_ap)
LEFT JOIN Aireports AS a1
ON f.target_ap = a1.airport_code)
LEFT JOIN
(
SELECT
ie.flight_code,
de1.actual_takeoff_date,
de1.actual_takeoff_time
FROM
Irregular_Events ie
INNER JOIN Event AS de1
ON ie.IE_code = de1.delay_code
) AS de
ON f.flight_code = de.flight_code
It is hard to tell what is the problem with your query without any sample of the output, and without any description of the structure of your tables.
But your problem is that your are querying from the flights table, which [I assume] can be linked to multiple irregular_events, which can possibly also be linked to multiple delay_event.
If you want to get only one row per flight, you need to make sure your joins return only one row too. Maybe you can do it by adding one more condition to the join, or by adding a condition in a sub-query.
EDIT
You could try to add a GROUP BY to the query:
GROUP BY
f.flight_code,
f.status,
a.airport_name,
a1.airport_name;

SQL - getting data twice from the same table

Good people of the internet, I need your help!
I'm trying to put together some SQL code to create a report. Basically, I'm needing to look at one table - tbl_Schedules - and fetch the maximum of the field SchedDone, which is a regular date field.
This is fair enough. I manage this using GROUP BY and MAX.
The same table also contains SchedFrom and SchedTo fields, and I need to get this from another record, but run alongside this.
Basically, I need a "LatestDate" field (which shows the max SchedDone), and then a "next scheduled" field (or fields), showing when it is next to be done, pulled from a row where the SchedDone is null.
My current code, displayed below (ignore everything but the tbl_Schedules stuff) is working to an extent. It shows the LatestDate as described above, but also shows the maximum of that Task's SchedFrom and SchedTo. These are all from different rows in the tbl_Schedules, which is what I want. I just need to know how to set up rules for the SchedFrom and SchedTo, preferably without involving any other tables or setting up multiple views.
I do have this working, but it's taking up several views and the speed involved is not good. I'd hope I can get it working in a single chunk of SQL code.
PS - tbl_PhysicalAssets is a one-to-many relationship with tbl_Operations (one row in tbl_PhysicalAssets to many in tbl_Operations), and tbl_Operations is a one-to-many relationship with tbl_Schedules (one row in tbl_Operations to many in tbl_Schedules).
Current code below (again, please ignore the other tables!) -
SELECT
dbo.tbl_PhysicalAsset.FKID_Contract,
dbo.tbl_PhysicalAsset.MyLevel,
dbo.tbl_PhysicalAsset.L1_Name,
dbo.tbl_PhysicalAsset.L2_Name,
dbo.tbl_PhysicalAsset.L3_Name,
dbo.tbl_OpList.Operation_Name,
dbo.tbl_Teams.Team_Name,
MAX(tbl_Schedules_1.SchedDone) AS LatestDate,
MAX(tbl_Schedules_1.SchedFrom) AS Expr1,
MAX(tbl_Schedules_1.SchedTo) AS Expr2
FROM
dbo.tbl_Schedules AS tbl_Schedules_1
RIGHT OUTER JOIN
dbo.tbl_PhysicalAsset
INNER JOIN
dbo.tbl_Operations ON dbo.tbl_PhysicalAsset.PKID_PhysicalAsset = dbo.tbl_Operations.FKID_PhysicalAsset
INNER JOIN
dbo.tbl_OpList ON dbo.tbl_Operations.FKID_Operation = dbo.tbl_OpList.PKID_Op
INNER JOIN
dbo.tbl_Teams ON dbo.tbl_Operations.FKID_Team = dbo.tbl_Teams.PKID_Team ON tbl_Schedules_1.FKID_Operation = dbo.tbl_Operations.PKID_Operation
GROUP BY
dbo.tbl_PhysicalAsset.FKID_Contract,
dbo.tbl_PhysicalAsset.MyLevel,
dbo.tbl_PhysicalAsset.L1_Name,
dbo.tbl_PhysicalAsset.L2_Name,
dbo.tbl_PhysicalAsset.L3_Name,
dbo.tbl_OpList.Operation_Name,
dbo.tbl_Teams.Team_Name
HAVING
(dbo.tbl_PhysicalAsset.FKID_Contract = 6)
AND (dbo.tbl_PhysicalAsset.MyLevel = 3)
This is rough as we don't know the exact details of your table structure.
But basically you need to first write the queries that get the two separate bits of information, make sure they work in isolation. You can then just join them together.
So something like (I've assumed FKID_Operation is the 'common' piece of info):
select
a.FKID_Operation
, b.LatestDate
, c.NextToDate
, c.NextFromDate
from tbl_Schedules a
inner join
(
select
m.FKID_Operation
, Max(m.SchedDone) as LatestDate
from tbl_Schedules m
where SchedDone is not null
) b
on a.FKID_Operation = b.FKID_Operation
inner join
(
select
n.FKID_Operation
, n.SchedTo as NextToDate
, n.SchedFrom as NextFromDate
from tbl_Schedules n
where SchedDone is null
) c
on a.FKID_Operation = c.FKID_Operation
I'd also look into CTE's as they can make this kind of query much easier to understand.

SQL statement structuring

I have two tables AgentFare and SalesHeader having hdrGuid and hdrGuid , DocumentNumber as columns respectively.
I have to perform a query based on Document number, however I am not able to figure out which of the two following queries are most suitable.
SELECT agf.Fare , agf.Tax . agf.Commission
FROM AgentFare as agf
INNER JOIN SalesHeader as h ON agf.hdrGuid = h.hdrGuid AND h.DocumentNumber = 'XYZ'
OR
SELECT agf.Fare , agf.Tax . agf.Commission
FROM AgentFare as agf
INNER JOIN SalesHeader as h ON agf.hdrGuid = h.hdrGuid
WHERE h.DocumentNumber = 'XYZ'
Which of the 2 are more appropriate ?
First method is more appropriate.Since it will take less time as compared to second query.
The "ON" statement should be used to define on what columns 2 tables should be joined.
The "WHERE" statement is intended to filter your results.
The second option is the more appropriate to use.
You might find that this is a case of personal preference. My preference is for the second one. It's clear to me what you are joining on and what you are filtering with. If you change your code so that you replace 'XYZ' with a parameter, then for me the second way is much easier. I expect to find the 'filters' at the bottom.

Why do I have to use DISTINCT for this to work?

here's my problem: I have an SQL query that makes 4 calls to a lookup table to return their values from a list of combinations in another table. I finally got this working, and for some reason, when I run the query without DISTINCT, I get a ton of data back, so I'm guessing that I'm either missing something or not doing this correctly. It would be really great if this would not only work, but also return the list alphabetically by the first colour name.
I'm putting my SQL here I hope I've explained this well enough:
SELECT DISTINCT
colour1.ColourID AS colour1_ColourID,
colour1.ColourName AS colour1_ColourName,
colour1.ColourHex AS colour1_ColourHex,
colour1.ManufacturerColourID AS colour1_ManufacturerColourID,
colour2.ColourID AS colour2_ColourID,
colour2.ColourName AS colour2_ColourName,
colour2.ColourHex AS colour2_ColourHex,
colour2.QEColourID2 AS colour2_QEColourID2,
colour3.ColourID AS colour3_ColourID,
colour3.ColourName AS colour3_ColourName,
colour3.ColourHex AS colour3_ColourHex,
colour3.QEColourID3 AS colour3_QEColourID3,
colour4.ColourID AS colour4_ColourID,
colour4.ColourName AS colour4_ColourName,
colour4.ColourHex AS colour4_ColourHex,
colour4.QEColourID4 AS colour4_QEColourID4,
Combinations.ID,
Combinations.ManufacturerColourID AS Combinations_ManufacturerColourID,
Combinations.QEColourID2 AS Combinations_QEColourID2,
Combinations.QEColourID3 AS Combinations_QEColourID3,
Combinations.QEColourID4 AS Combinations_QEColourID4,
Combinations.ColourSupplierID,
ColourSuppliers.ColourSupplier
FROM
ColourSuppliers INNER JOIN
(
colour4 INNER JOIN
(
colour3 INNER JOIN
(
colour2 INNER JOIN
(
colour1 INNER JOIN Combinations ON
colour1.ColourID=Combinations.ManufacturerColourID
) ON colour2.ColourID=Combinations.QEColourID2
) ON colour3.ColourID=Combinations.QEColourID3
) ON colour4.ColourID=Combinations.QEColourID4
) ON ColourSuppliers.ColourSupplierID=Combinations.ColourSupplierID
WHERE Combinations.ColourSupplierID = ?
Thanks
Steph
It looks as though you've probably got multiple records for each set of four colour combinations in the Combinations table - posting the structure of the table might help us to work it out.
Adding the clause order by colour1.ColourName to the end of the query should sort it alphabetically by the first colour name.
My guess (and it is a guess because your SQL query is very wide!) is that you're getting the cartesian product.

Trying to use table aliases in SQL

I'm a graphic designer trying my best to understand table aliases, but it's not working.
Here's what I have so far:
SELECT colours.colourid AS colourid1,
combinations.manufacturercolourid AS colourmanid1,
colours.colourname AS colourname1,
colours.colourhex AS colourhex1,
combinations.qecolourid2 AS colouridqe2,
colours.colourid AS colourid2,
colours.colourname AS colourname2,
colours.colourhex AS colourhex2,
colours.colourid AS colourid3,
combinations.qecolourid3 AS colouridqe3,
colours.colourname AS colourname3,
colours.colourhex AS colourhex3,
colours.colourid AS colourid4,
combinations.qecolourid4 AS colouridqe4,
colours.colourname AS colourname4,
colours.colourhex AS colourhex4,
combinations.coloursupplierid
FROM combinations
INNER JOIN colours
ON colours.colourid = combinations.manufacturercolourid;
Now, the idea is that in the colours lookup table, the id will pull the colour code, hex and name from the lookup table so that I can pull the colour code, hex and name for the 4 colours that I'm looking for. I can get this to work, but it only pulls up the first name, code and hex and I'm just not seeing what I'm doing wrong.
Your problem is that you are linking in only a single record from the colours table because you only have a single JOIN in your SQL. That record will match the color specified by manufacturer_colour_id.
You may also have a further problem in that your combinations table does not appear to be in proper normal form (although I could be wrong, not knowing the actual nature of the data you're trying to represent).
If I understand your problem correctly, the solution (using your current table structures) will be something more like:
SELECT C1.colourid AS colourid1,
CMB.manufacturercolourid AS colourmanid1,
C1.colourname AS colourname1,
C1.colourhex AS colourhex1,
CMB.qecolourid2 AS colouridqe2,
C2.colourid AS colourid2,
C2.colourname AS colourname2,
C2.colourhex AS colourhex2,
C3.colourid AS colourid3,
CMB.qecolourid3 AS colouridqe3,
C3.colourname AS colourname3,
C3.colourhex AS colourhex3,
C4.colourid AS colourid4,
CMB.qecolourid4 AS colouridqe4,
C4.colourname AS colourname4,
C4.colourhex AS colourhex4,
CMB.coloursupplierid
FROM combinations CMB
LEFT OUTER JOIN colours C1
ON C1.colourid = CMB.manufacturercolourid
LEFT OUTER JOIN colours C2
ON C2.colourid = CMB.qecolourid2
LEFT OUTER JOIN colours C3
ON C3.colourid = CMB.qecolourid3
LEFT OUTER JOIN colours C4
ON C4.colourid = CMB.qecolourid4
What's happening here is that I'm linking the colours table four times, once for each of the colour_id fields in the combinations table. To do so, I need to alias the table name each time so that I know which of the four possible instances of colours to use in the list of returned columns. Also, I'm using OUTER JOINs in the event that one or more colour_id columns might be empty. If that happened with INNER JOINs, the entire row would drop out of the result set.
You can use table aliases to reduce the amount of typing needed - by adding something like this:
SELECT
cl.colourid AS colourid1,
cb.manufacturercolourid AS colourmanid1,
cl.colourname AS colourname1,
... and so on.....
FROM
combinations AS cb
INNER JOIN
colours AS cl ON cl.colourid = cb.manufacturercolourid;
By defining a table alias cb for your table combinations, you can use that shorter alias in your SELECT and other parts of your statement, instead of having to always spell out the entire table name.
But your problem really is in the JOIN - you're only joining once, yet you expect to get four results back....
What you need to do is something like this:
SELECT
col1.colourid AS colourid1,
cb.manufacturercolourid AS colourmanid1,
col1.colourname AS colourname1,
col1.colourhex AS colourhex1,
cb.qecolourid2 AS colouridqe2,
col2.colourid AS colourid2,
col2.colourname AS colourname2,
col2.colourhex AS colourhex2,
col2.colourid AS colourid3,
cb.qecolourid3 AS colouridqe3,
col3.colourname AS colourname3,
col3.colourhex AS colourhex3,
col3.colourid AS colourid4,
cb.qecolourid4 AS colouridqe4,
col4.colourname AS colourname4,
col4.colourhex AS colourhex4,
cb.coloursupplierid
FROM
combinations cb
INNER JOIN colours AS col1 ON col1.colourid = cb.manufacturercolourid
INNER JOIN colours AS col2 ON col2.colourid = cb.qecolourid2
INNER JOIN colours AS col3 ON col3.colourid = cb.qecolourid3
INNER JOIN colours AS col4 ON col4.colourid = cb.qecolourid4
This is not an exhaustive answer, but your problem has to do with your how you are using the JOINs. Table and column aliases do not affect the output result set.
You are selecting the same field names four times, and that is why you are getting strange results.
These are all great, but for some reason when I try to use them, I get an error in the page:
[Microsoft][ODBC Microsoft Access Driver] Syntax error (missing operator) in query expression
I think I understand how to use the table aliases now, but for some reason, even though I'm sure it should work, the page doesn't like it.