SQL Selecting from one table with WHERE clause on the joined tables - sql

I have three tables. The TestOptionsTable contains a list of tests to be performed on an instrument.
The second table CreateScript, is a table to store scripts to run during testing. These scripts contain a selection of some of the tests stored in TestOptionsTable. The scripts are run and the tests appear on screen one by one.
The results of each test are entered on screen and stored in TestResultsTable. When saved, the column IsTestComplete, is marked with a 1 and has a datatype of BIT.
During a script being run, the user may be interrupted and some individual tests may not yet be carried out. When the tests resume I want to display a list of tests from a script that have yet to be completed. Essentially select data from TestOptions and CreateScript if there is no entry for that Test in the results Table. So far I have this but is not returning anything:
select TestType,TestName, Limits
FROM CreateScriptTable
inner join TestOptionsTable on CreateScriptTable.TestName = TestOptionsTable.TestName
inner join TestResultsTable on CreateScriptTable.TestName = TestResultsTable.TestName
WHERE CreateScriptTable.InstrumentType= 'Instrument1'
AND TestResultsTable.IsTestComplete <> 1
ORDER BY [Index] ASC, TestName
The idea is that data is returned if the IsTestComplete Column has not been set to true in the results table but no data is returned. Has anyone any ideas? Thanks!
EDIT:
Expected output is something like below. With test Name, category and limits of test
Full Test 1 Visual 10 12
test1 Visual 0.1 0.22
Test 34 Visual 121 2222
Flow Test As Found 1 1.2
Test 2 As Found 1 1.1
Test 3 As Left 85 105
Test 6 As Left 95 103
Any incomplete tests will not be in the Test Results Table. I would like to select from CreateScript any tests that are not in the results table.

You say
Any tests that are incomplete will not be present at all in the
Results Table.
this means that you cannot use a INNER JOIN to relate the two first tables with the results.
Probably you should rewrite your query with a LEFT JOIN like this
select TestType,TestName, Limits
FROM CreateScriptTable
inner join TestOptionsTable on CreateScriptTable.TestName = TestOptionsTable.TestName
left join TestResultsTable on CreateScriptTable.TestName = TestResultsTable.TestName
WHERE CreateScriptTable.InstrumentType= 'Instrument1'
AND TestResultsTable.IsTestComplete IS NULL
ORDER BY [Index] ASC, TestName

Related

How to join 2 tables with multiple conditions each?

I have data split between 2 tables, and need to join the necessary data together for analysis.
One table Test 3 Output contains ID numbers, and the return value of the test. The other table Test Results contains the same IDs, along with their corresponding serial number and overall test result.
I need to combine these into a single table that just displays ID, serial number and test value.
Sorry in advance for the horrible SQL thats about to follow, I'm brand new to this.
I have 2 working queries that give me what I want, but I can't seem to join them together.
The first query:
select `ID`,`Serial Number` from `Test Results`t where (len(`Serial Number`)=16 and FailMode = '24V Supply FAIL')
This gets me the ID and serial number of all the tests that failed '24V supply'. It also filters out garbage serial numbers as the correct ones should have 16 digits.
The second query:
select `ID` from `Test 3 Output`o where o.`24V Supply (V)`<30
This gets me the ID and test results, and filters out some results that were greater than 30V. Note that '24V Supply(V) is the name of the column containing the test results.
Now when I try to join these with the ID, I get a syntax error. Here's what I tried:
select `ID`,`Serial Number`
from `Test Results`t
where (len(`Serial Number`)=16 and FailMode = '24V Supply FAIL')
left join (`Test 3 Output`o ON t.`ID` = o.`ID` where o.`24V Supply (V)`<30)
This gives the error:
Error: Syntax error (missing operator) in query expression (len(`Serial Number`)=16 and FailMode = '24V Supply FAIL') left join (`Test 3 Output`o ON t.`ID` = o.`ID` where o.`24V Supply (V)`<30)
I'm not sure what operator I'm missing but I had a feeling its related to the fact there's two where statements?
Can anyone offer some help?
Edit: I found a workaround since I can't use 2 where clauses with a join. I created 2 views with my 2 separate queries, and performed the join on those which got me what I wanted. I'd still like to hear a proper way of doing it though :)
You can join 2 subqueries like this:
SELECT q1.a, q1.b, q2.c
FROM (
(SELECT a, b FROM table1
WHERE b > 10) AS q1
LEFT JOIN
(SELECT a, c FROM table2
WHERE c > 20) AS q2
ON q1.a = q2.a
)
Doing the subqueries as separate query objects is easier to debug, but the query objects keep piling up...

SQL query for crystal reports produces duplicate results

I created 3 tables TstInvoice, TstProd, TstPersons and added some data:
INVOICE_NBR CLIENT_NR VK_CONTACT
A10304 003145 AT
A10305 000079 EA
A10306 004458 AT
A10307 003331 JDJ
PROD_NR INVOICE_NBR
P29366 A10304
P29367 A10304
P29368 A10305
P29369 A10306
P29370 A10306
P29371 A10307
PERS_NR INITIALEN STATUS PERSOON
0001 AT 7 Alice Thompson
0002 EA 1 Edgar Allen
0003 JDJ 1 John Doe Joe
0004 AT 1 Arthur Twins
The parameter that is passed to the crystal report is the INVOICE_NBR.
On my crystal report I put some fields from the databases and one sql expression:
(
SELECT "TstPersons"."PERSOON" FROM "TstPersons"
WHERE "TstPersons"."INITIALEN" = "TstInvoice"."VK_CONTACT" AND "TstPersons"."STATUS" = 1
)
The full query that is generated:
SELECT "TstInvoice"."INVOICE_NBR", "TstInvoice"."CLIENT_NR", "TstPersons"."STATUS", "TstPersons"."PERSOON", "TstProd"."PROD_NR", "TstProd"."INVOICE_NBR", (
SELECT "TstPersons"."PERSOON" FROM "TstPersons"
WHERE "TstPersons"."INITIALEN" = "TstInvoice"."VK_CONTACT" AND "TstPersons"."STATUS" = 1
)
FROM ("GCCTEST"."dbo"."TstInvoice" "TstInvoice" INNER JOIN "GCCTEST"."dbo"."TstProd" "TstProd" ON "TstInvoice"."INVOICE_NBR"="TstProd"."INVOICE_NBR") INNER JOIN "GCCTEST"."dbo"."TstPersons" "TstPersons" ON "TstInvoice"."VK_CONTACT"="TstPersons"."INITIALEN"
WHERE "TstInvoice"."INVOICE_NBR"='A10304'
The result is as shown in the screenshot:
As you can see the TstPersons.PERSOON field is populated with Alice Thompson and the sql expression field is correctly populated with Arthur Twins. However, I would like only to see the prod_nr once. With this query it produces the prod numbers twice because of the double entry for "AT" despite the fact that I ask for only status 1. I could just delete the old entry but I want to know if it's possible this way.
* edit * I added the status = 1 to the "record selection formula editor" and that seems to work. Not need the sql expression field at all. Not sure if this is the correct way to go though.
So now it looks like this:
SELECT "TstInvoice"."INVOICE_NBR", "TstInvoice"."CLIENT_NR", "TstPersons"."STATUS", "TstPersons"."PERSOON", "TstProd"."PROD_NR", "TstProd"."INVOICE_NBR"
FROM ("GCCTEST"."dbo"."TstInvoice" "TstInvoice" INNER JOIN "GCCTEST"."dbo"."TstProd" "TstProd" ON "TstInvoice"."INVOICE_NBR"="TstProd"."INVOICE_NBR") INNER JOIN "GCCTEST"."dbo"."TstPersons" "TstPersons" ON "TstInvoice"."VK_CONTACT"="TstPersons"."INITIALEN"
WHERE "TstInvoice"."INVOICE_NBR"='A10304' AND "TstPersons"."STATUS"=1
You have a very weak join in your query due to the duplicate values found in the INITIALEN column. Using the STATUS = 1 criteria is a work-around more than a solution because if you ever need to report on an invoice where the contact has a status other than 1, you will need to modify the report's design to allow your join to work because the STATUS value is not found on the invoice to allow a proper join to occur.
You are also running a risk of this work-around breaking down completely should you have another contact with both the same initials and status values as another.
The correct way to solve this problem would be to join TstInvoice to TstPersons through a field that has unique values. The PERS_NR column appears to be a good choice for this.
This is also going to require a redesign of the TstInvoice table to include the PERS_NR column as a Foreign Key.
A stronger join between invoices and persons would also remove the need for that sub-query in you selection statement. This would simplify your query down to the following:
SELECT "TstInvoice"."INVOICE_NBR", "TstInvoice"."CLIENT_NR", "TstPersons"."STATUS", "TstPersons"."PERSOON", "TstProd"."PROD_NR", "TstProd"."INVOICE_NBR"
FROM "GCCTEST"."dbo"."TstInvoice" "TstInvoice"
INNER JOIN "GCCTEST"."dbo"."TstProd" "TstProd"
ON "TstInvoice"."INVOICE_NBR"="TstProd"."INVOICE_NBR"
INNER JOIN "GCCTEST"."dbo"."TstPersons" "TstPersons"
ON "TstInvoice"."PERS_NR"="TstPersons"."PERS_NR"
WHERE "TstInvoice"."INVOICE_NBR"='A10304'

how to join multiple tables without showing repeated data?

I pop into a problem recently, and Im sure its because of how I Join them.
this is my code:
select LP_Pending_Info.Service_Order,
LP_Pending_Info.Pending_Days,
LP_Pending_Info.Service_Type,
LP_Pending_Info.ASC_Code,
LP_Pending_Info.Model,
LP_Pending_Info.IN_OUT_WTY,
LP_Part_Codes.PartCode,
LP_PS_Codes.PS,
LP_Confirmation_Codes.SO_NO,
LP_Pending_Info.Engineer_Code
from LP_Pending_Info
join LP_Part_Codes
on LP_Pending_Info.Service_order = LP_Part_Codes.Service_order
join LP_PS_Codes
on LP_Pending_Info.Service_Order = LP_PS_Codes.Service_Order
join LP_Confirmation_Codes
on LP_Pending_Info.Service_Order = LP_Confirmation_Codes.Service_Order
order by LP_Pending_Info.Service_order, LP_Part_Codes.PartCode;
For every service order I have 5 part code maximum.
If the service order have only one value it show the result correctly but when it have more than one Part code the problem begin.
for example: this service order"4182134076" has only 2 part code, first'GH81-13601A' and second 'GH96-09938A' so it should show the data 2 time but it repeat it for 8 time. what seems to be the problem?
If your records were exactly the same the distinct keyword would have solved it.
However in rows 2 and 3 which have the same Service_Order and Part_Code if you check the SO_NO you see it is different - that is why distinct won't work here - the rows are not identical.
I say you have some problem in one of the conditions in your joins. The different data is in the SO_NO column so check the raw data in the LP_Confirmation_Codes table for that Service_Order:
select * from LP_Confirmation_Codes where Service_Order = 4182134076
I assume you are missing an and with the value from the LP_Part_Codes or LP_PS_Codes (but can't be sure without seeing those tables and data myself).
By this sentence If the service order have only one value it show the result correctly but when it have more than one Part code the problem begin. - probably you are missing and and with the LP_Part_Codes table
Based on your output result, here are the following data that caused multiple output.
Service Order: 4182134076 has :
2 PartCode which are GH81-13601A and GH96-09938A
2 PS which are U and P
2 SO_NO which are 1.00024e+09 and 1.00022e+09
Therefore 2^3 returns 8 rows. I believe that you need to check where you should join your tables.
Use DINTINCT
select distinct LP_Pending_Info.Service_Order,LP_Pending_Info.Pending_Days,
LP_Pending_Info.Service_Type,LP_Pending_Info.ASC_Code,LP_Pending_Info.Model,
LP_Pending_Info.IN_OUT_WTY, LP_Part_Codes.PartCode,LP_PS_Codes.PS,
LP_Confirmation_Codes.SO_NO,LP_Pending_Info.Engineer_Code
from LP_Pending_Info
join LP_Part_Codes on LP_Pending_Info.Service_order = LP_Part_Codes.Service_order
join LP_PS_Codes on LP_Part_Codes.Service_Order = LP_PS_Codes.Service_Order
join LP_Confirmation_Codes on LP_PS_Codes.Service_Order = LP_Confirmation_Codes.Service_Order
order by LP_Pending_Info.Service_order, LP_Part_Codes.PartCode;
distinct will not return duplicates based on your select. So if a row is same, it will only return once.

SQL query - how do I restrict to the rows I'm interested in

I have the following tables - simplified quite a bit
Table - Tests
Test
A
B
C
D
E
F
G
H
Table - TestHistory
Test Result Version
A Pass 1
A Fail 2
B Pass 2
C Fail 1
C Pass 2
D Fail 1
D Fail 2
E Fail 1
I want to get the list of tests that failed (or any status) the last time they ran. But, also the version that it was found in.
So, in the above example, I want this returned:
A Fail 2
D Fail 2
E Fail 1
I've tried a couple methods
select Test, LastResult = IsNull((Select Top 1 Result From TestHistory Where Test = Tests.Test order by Version desc), 'NOT_RUN')
from Tests
What this does, is gives me a list of all tests and then I have to go through and kick out the rows I don't want (i.e. isn't Fail). This also doesn't give me the Version it ran in.
I also tried this:
select Version, TH.Test, Result
from TestHistory as TH inner join Tests as T on TH.Test = T.Test
where Result = 'Fail'
But, then I get rows such as:
Test Result Version
C Fail 1
I don't want those because it's not the Last Result.
How can I restrict this to give me exactly what I need without a lot of data manipulation (or worse, more DB reads) after? Any help would be appreciated. Thanks!
I can't syntax check this, but it should be close:
SELECT
th.Test,
th.Result,
th.Version
FROM
TestHistory th
INNER JOIN
(
SELECT
MAX(Version) as MaxVersion,
Test
FROM
TestHistory
GROUP BY
Test
) sub ON sub.MaxVersion = th.Version AND sub.Test = th.Test
WHERE
th.result = 'Fail'
Explanation: First, in the subquery, you get the maximum version for the test. Then use a join to restrict the outer query to only return the results that match the test/version of the subquery.
Edit: forgot the WHERE clause--seems you only want rows where the most recent result is failure.
Edit based on the question in your comment:
This should give you the most recent failure, plus tests that have never run. Note that this will filter out tests that have run but have never failed (your data does not have any of these). I based this on my original query in the interest of time, but I would guess there is a more elegant way:
SELECT
t.Test,
outerSub.Result,
outerSub.Version
FROM
Test t
LEFT JOIN
(SELECT
th.Test,
th.Result,
th.Version
FROM
TestHistory th
INNER JOIN
(
SELECT
MAX(Version) as MaxVersion,
Test
FROM
TestHistory
GROUP BY
Test
) sub ON sub.MaxVersion = th.Version AND sub.Test = th.Test
) outerSub on outerSub.Test = t.Test
WHERE
outerSub.result = 'Fail' OR outerSub.Test IS NULL
Small correction can be added to the above solution.
In case when You need to receive the results in the Test order, the query can be transformed as below:
SELECT src.Test, src.Result, src.Version
FROM
(
SELECT th.Version, th.Test, th.Result,
ROW_NUMBER() over(partition by th.Test order by th.Version desc) as RowNum
FROM dbo.TestHistory as th
) src
WHERE src.RowNum = 1 and src.Result = 'Fail'
order by src.Test;
Among this, the query will return the set in the needed columns' order.
How about:
select th.* from testHistory th
where th.result = 'fail' -- this part, according to you, being optional
and th.version =
(select max(t.version) from testhistory t
where t.test = th.test);

SQL Server returns empty fields

I have a select script that runs 3 times a day in a 2005 SQL Server installation, a few times the return table has contained expected number of rows but without any values. The integer and date fields have zeros and the others are simply blank.
Since the problem occurs very rarely there is no way to supervise the database when the script runs and haven't been able to replicate the issue. My thought is that some other update in the database is causing the problem. Does anyone know about this problem?
Here is the script
SELECT DISTINCT
URL.Line,
RTrim(URL.DescriptionNote) AS [DescriptionNote],
SA1.Name AS [Name1],
SP1.Designation AS [Designation1],
SA2.Name [Name2],
SP2.Designation AS [Designation2],
RL.DistanceMeters,
dbo.RouteLinkTransportModeDesc(URL.TransportModeTypeNumber) AS TransportMode,
URL.THM,
URL.FirstWorkedDate,
URL.LastWorkedDate
FROM #RequiredRouteLink URL
INNER JOIN StopPoint AS SP1
ON SP1.JourneyPatternPointGid = URL.StartsAtPointGid
INNER JOIN StopArea AS SA1
ON SP1.IsPartOfStopAreaVersionId = SA1.VersionId
INNER JOIN StopPoint AS SP2
ON SP2.JourneyPatternPointGid = URL.EndsAtPointGid
INNER JOIN StopArea AS SA2
ON SP2.IsPartOfStopAreaVersionId = SA2.VersionId
LEFT JOIN verRouteLink AS RL
ON RL.StartsAtPointGid = URL.StartsAtPointGid
AND RL.EndsAtPointGid = URL.EndsAtPointGid
AND URL.TransportModeTypeNumber = RL.TransportModeTypeNumber
WHERE URL.StartsAtPointGid <> URL.EndsAtPointGid
AND (RL.EndsAtPointGid IS NULL OR RL.DistanceMeters = 0 OR RL.DistanceMeters IS NULL)
AND RL.[DeletedDateTime] IS NULL
ORDER BY FirstWorkedDate, THM, TransportMode, Line, DescriptionNote
I'm sure it is a data issue. The reason you are getting blank fields is most likely the LEFT JOIN.
You have 4 INNER JOINs, any one of which could cause you to have an empty result set. If one or more of those don't find a match, you have no results.
However, your LEFT JOIN means you will at least get the list of URL.Line, which is why you had the expected number of rows most likely.
Can you run a low level SQL trace - filtering it as much as possible to reduce the load of the trace [e.g., by application, etc.]