How to self join this SQL - sql

I have one table in my Database that has column names: buildNumber, result, versionStatus. Now in my SQL statement I want to display the 'buildNumber' where the 'versionStatus' is old and the 'result' is pass and where the versionStatus is new and the result is 'fail'. So I want to display anything that has a result of fail today but had a result of pass last time. So if I have these records in the DB (column separated by --):
build2--pass--old
build2--fail--new
The SQL statement should only display "build2" because it passed with "old" but now 'failed' with new version.
I have tried:
select *
from CSAResults.dbo.Details
where result = 'pass'
and versionStatus = 'Old'
and versionStatus IN (select CSAResults.dbo.Details.versionStatus
from CSAResults.dbo.Details
where versionStatus = 'New'
and result = 'fail')
but nothing is returned.
Thanks

This query does a self-joins of Details table to get the result you want.
SELECT distinct new.buildNumber
FROM CSAResults.dbo.Details old
JOIN CSAResults.dbo.Details new ON old.buildNumber = new.buildNumber
WHERE old.result = 'pass'
AND old.versionStatus = 'Old'
AND new.result='fail'
AND new.versionStatus='New'
I added the distinct in the select clause so you wouldn't get duplicate results if there were multiple old versions of the build that had passed

Your existing query should work if you change the IN condition to be:
and buildNumber IN (select CSAResults.dbo.Details.buildNumber
Alternatively, a better performing query might be:
Select buildNumber
from CSAResults.dbo.Details
group by buildNumber
having count(distinct case
when result = 'pass' and versionStatus = 'Old' then 1
when result = 'fail' and versionStatus = 'New' then 2
end) = 2

An alternative would be to use an INNER JOIN as so:
select t.*
from CSAResults.dbo.Details t INNER JOIN (SELECT t2.buildNumber
FROM CSAResults.dbo.Details t2
WHERE t2.versionStatus = 'New'
and t2.result = 'fail') t1
ON t.buildNumber = t1.buildNumber
where t.result = 'pass'
and t.versionStatus = 'Old'

Nothing returned? Hardly surprising: you're trying to assert
(VersionStatus='New') = (VersionStatus='Old')
Try something like this instead
select *
from CSAResults.dbo.Details
where result = 'pass'
and versionStatus = 'Old'
and buildNumber IN (select CSAResults.dbo.Details.buildNumber from CSAResults.dbo.Details
where versionStatus = 'New'
and result = 'fail')

Related

Case when statement while using in join condition not working in oracle

I need to use case when on join statement in sql.I tried, but I am getting error as:
Missing expression:ORA-00905
I tried this query:
SELECT *
FROM abc a
LEFT JOIN (SELECT *
FROM anil_groups
WHERE datatype = 'C'
AND payor = 'SELECT') gr
ON CASE
WHEN Upper(a.sourcefilename) LIKE '%RIO%' THEN
gr.sourceid = 'SH_Rio_Tinto'
ELSE gr.sourceid = 'SH_Albertson'
END
LEFT JOIN (SELECT *
FROM tbl_danger
WHERE source = 'KK') spec
ON Upper(a.rollupid) = spec.code;
It doesnt work like that in oracle. CASE WHEN is a construct that provides a non boolean value, so you have to use it to run your boolean test (Upper(a.sourcefilename) LIKE '%RIO%') and have it produce the string value you want to compare to gr.sourceid:
ON gr.sourceid = CASE
WHEN Upper(a.sourcefilename) LIKE '%RIO%' THEN
'SH_Rio_Tinto'
ELSE 'SH_Albertson'
END
You can also rewrite your join not to use it:
ON (gr.sourceid = 'SH_Rio_Tinto' AND Upper(a.sourcefilename) LIKE '%RIO%') OR
(gr.sourceid = 'SH_Albertson' AND Upper(a.sourcefilename) NOT LIKE '%RIO%')

Using a CASE WHEN statement and an IN (SELECT...FROM) subquery

I'm trying to create a temp table and build out different CASE WHEN logic for two different medications. In short I have two columns of interest for these CASE WHEN statements; procedure_code and ndc_code. There are only 3 procedure codes that I need, but there are about 20 different ndc codes. I created a temp.ndcdrug1 temp table with these ndc codes for medication1 and temp.ndcdrug2 for the ndc codes for medication2 instead of listing out each ndc code individually. My query looks like this:
CREATE TABLE temp.flags AS
SELECT DISTINCT a.userid,
CASE WHEN (procedure_code = 'J7170' OR ndc_code in (select ndc_code from temp.ndcdrug1)) THEN 'Y' ELSE 'N' END AS Drug1,
CASE WHEN (procedure_code = 'J7205' OR procedure_code = 'C9136' OR ndc_code in (select ndc_code from temp.ndcdrug2)) THEN 'Y' ELSE 'N' END AS Drug2,
CASE WHEN (procedure_code = 'J7170' AND procedure_code = 'J7205') THEN 'Y' ELSE 'N' END AS Both
FROM table1 a
LEFT JOIN table2 b
ON a.userid = b.userid
WHERE...
AND...
When I run this, it returns: org.apache.spark.sql.AnalysisException: IN/EXISTS predicate sub-queries can only be used in a Filter.
I could list these ndc_code values out individually, but there are a lot of them so wanted a more efficient way of going about this. Is there a way to use a sub select query like this when writing out CASE WHEN's?
Query.
CREATE TABLE temp.flags AS
SELECT DISTINCT a.userid,
CASE WHEN (
procedure_code = 'J7170' OR
(select min('1') from temp.ndcdrug1 m where m.ndc_code = a.ndc_code) = '1'
) THEN 'Y' ELSE 'N' END AS Drug1,
CASE WHEN (
procedure_code = 'J7205' OR
procedure_code = 'C9136' OR
(select min('1') from temp.ndcdrug2 m where m.ndc_code = a.ndc_code) = '1'
) THEN 'Y' ELSE 'N' END AS Drug2,
CASE WHEN (procedure_code = 'J7170' AND procedure_code = 'J7205')
THEN 'Y' ELSE 'N' END AS Both
FROM table1 a
LEFT JOIN table2 b
ON a.userid = b.userid
WHERE...
AND...

Is it possible to have multiple CASE in a GROUP BY that can make it so it doesn't group at all?

I'm trying to query come datas and on a spcific case I might have to group datas by multiple values. But most of the time it needs not to be grouped at all. So I'm using multiple CASE WHEN {...} inside the GROUP BY, and all the WHEN basically have the same condition. The problem is that if the condition is met, everything works fine. But if it's false, then the GROUP BY section is empty and the query returns only the first row.
I basically tried to reorganize the quesry in every way that came to my mind, nothing seemed to work, and I didn't find anything conclusive on internet.
I'm using MySql 5.7.
SELECT
{element I want to select}
FROM
{tables}
WHERE
{conditions}
GROUP BY
CASE WHEN (condition) THEN [table].[column] END,
CASE WHEN (condition) THEN [table].[column] END,
CASE WHEN (condition) THEN [table].[column] END
ORDER BY
{...}
Full query :
SELECT
tx.code,
IFNULL(hr.label,'') AS rh_label,
IFNULL(cli.label,'') AS client_label,
DATE(FROM_UNIXTIME(created.value / 1000)) AS Created,
IFNULL(item_enfant.label,'') As Parasite,
IFNULL(item_parent.label,'') As Zone,
CASE
WHEN :perWeek = 'week' THEN SUM(qte.value)
ELSE qte.value
END AS Quantite,
CEILING(DATEDIFF(DATE(FROM_UNIXTIME(created.value / 1000)), DATE(FROM_UNIXTIME(:from / 1000))) / 7) AS Weeks
FROM tx
LEFT JOIN tx_type AS tt ON tt.id = tx.tx_type_id
LEFT JOIN human_resource AS hr ON hr.id = tx.human_resource_id
LEFT JOIN client AS cli ON cli.id = tx.client_id
LEFT JOIN tx_state AS ts ON ts.id = tx.current_tx_state_id
LEFT JOIN workflow_step AS ws ON ws.id = ts.workflow_step_id
LEFT JOIN item AS item_enfant ON item_enfant.item_list_id = tx.item_list_id
JOIN item_type AS ite ON ite.id = item_enfant.item_type_id
LEFT JOIN item_meta AS qte ON qte.item_id = item_enfant.id AND qte.name = 'qtePourRapport'
LEFT JOIN item_prop AS created ON created.item_id = item_enfant.id AND created.name = 'visite.timestamp'
JOIN item AS item_parent ON item_parent.id = item_enfant.parent_item_id
JOIN item_type AS itp ON itp.id = item_parent.item_type_id
WHERE
ite.name = 'parasite' AND
item_enfant.product_id IN (:parasiteIds) AND
itp.name = 'zone' AND
item_parent.product_id IN (:zoneIds) AND
cli.id = (:clientId) AND
ws.logic_id = 600 AND
created.value BETWEEN :from AND :to AND
created.value IS NOT NULL AND qte.value IS NOT NULL
GROUP BY
CASE WHEN :perWeek = 'week' THEN item_enfant.label END, #Parasite
CASE WHEN :perWeek = 'week' THEN item_parent.label END, #Zone
CASE WHEN :perWeek = 'week' THEN CEILING(DATEDIFF(DATE(FROM_UNIXTIME(created.value / 1000)), DATE(FROM_UNIXTIME(:from / 1000))) / 7) END #Weeks
ORDER BY
Created;
I'm getting the datas of the first row alone. And I actually have no idea how to get it just not to group if the condition is not met.
You need a unique value for the aggregation or two separate queries. The simplest method might be union all:
select . . .
from t
where <conditions not to group by>
union all
select . . .
from t
where <conditions to group by>
group by . . .;
You need to be sure that each subquery returns compatible columns.
SELECT
{element I want to select}
FROM
{tables}
WHERE
{conditions}
GROUP BY
CASE WHEN (condition) THEN [table].[column] ELSE [some unique value of same data-type as column] END,
CASE WHEN (condition) THEN [table].[column] ELSE [some unique value of same data-type as column] END,
CASE WHEN (condition) THEN [table].[column] ELSE [some unique value of same data-type as column] END
ORDER BY
{...}
I guess the missing ELSE clause will evaluate to NULL. This is constant, thus all rows will be in the same group, thus there will be only one row returned for this group. To avoid grouping you need unique values over all returned rows in the combination of the grouping-elements (not in every single grouping-element as stated erlier).
EDIT
Thus the soultion from the comment might be easier: Just add another grouping-element CASE WHEN !(condition) THEN CONCAT([different elements making it unique]) END

How to use a non-existing column in sql query

I am working in SQL server 2012. I have to write a sql statement where I first assign a value to [Pay_Type], which is a non-existing column (not sure whether it can be called as variable or not) and based upon its value I want to use it in another case statement as shown below
SELECT sp.First_Name, [Pay_Type] = CASE WHEN NOT EXISTS(SELECT '1' FROM
PERSON_SALARY ps WHERE ps.PARTY_ID = sp.PARTY_ID and ps.END_DATE IS NULL)
THEN 'Hourly' ELSE 'Salary' END,
HOURLY_RATE = CASE WHEN [Pay_Type] = 'Hourly' THEN pj.HOURLY_RATE ELSE
'0.00' END
FROM SEC_PERSON sp
LEFT OUTER JOIN PERSON_JOB pj ON sp.PERSON_ID = pj.PERSON_ID
WHERE sp.END_DATE IS NOT NULL
But I am getting "Invalid column name 'Pay_Type' " error.
Column aliases cannot be re-used in the same SELECT where they are define. The typical answer is to use a subquery or CTE. I also like using a lateral join:
SELECT sp.First_Name, s.Pay_Type,
HOURLY_RATE = (CASE WHEN s.Pay_Type = 'Hourly' THEN pj.HOURLY_RATE ELSE
'0.00' END)
FROM SEC_PERSON sp LEFT OUTER JOIN
PERSON_JOB pj
ON sp.PERSON_ID = pj.PERSON_ID OUTER APPLY
(SELECT (CASE WHEN NOT EXISTS (SELECT 1
FROM PERSON_SALARY ps
WHERE ps.PARTY_ID = sp.PARTY_ID and ps.END_DATE IS NULL
)
THEN 'Hourly' ELSE 'Salary'
END) as PayType
) s
WHERE sp.END_DATE IS NOT NULL

TSQL Select element with only one value

I have a project in which I need to save request for file. I have to save the state of the request with the date of each step.
I have two tables in my database :
FileRequest :
FileRequestStatus :
I would like to create a request to get each FileName from the table FileRequest having only the Status == 'NEW'. The desired output would be in this case C12345, LIVE.
If you have a better idea in order to build my database, I'll take it
I tried something like that :
SELECT [FileName] FROM [FileRequest]
INNER JOIN [FileRequestStatus] ON [FileRequestStatus].[RequestId] = [FileRequest].[RequestId]
GROUP BY [FileRequestStatus].[RequestId]
HAVING COUNT([FileRequestStatus].[RequestStatus]) < 2
SELECT FR.FileName
FROM [FileRequest] FR
INNER JOIN [FileRequestStatus] FRS ON FRS.[RequestId] = FR.[RequestId]
GROUP BY FR.FileName
HAVING COUNT(CASE WHEN FRS.RequestStatus <> 'New' THEN 1 END) = 0 --No statuses other than `NEW`
AND COUNT(CASE WHEN FRS.RequestStatus = 'New' THEN 1 END) >= 1 --Atleast one status `NEW`
I think the simplest method is aggregation:
select fr.FileName
from nep.FileRequest fr join
nep.FileRequestStatus] frs
on frs.RequestId = fr.RequestId
group by fr.FileName
having min(frs.RequestStatus) = max(frs.RequestStatus) and
min(frs.RequestStatus) = 'New';
Note: This assumes that the request status is never NULL (although that is easy to take into account).
What this does is aggregate by file name and then check that the statuses for a given file are all equal (the first condition) and equal to 'New' (the second condition).
You need to include [FileName] to your GROUP BY, then you can select it in result
SELECT [nep].[FileRequest].[FileName] FROM [nep].[FileRequest]
INNER JOIN [nep].[FileRequestStatus] ON [nep].[FileRequestStatus].[RequestId] = [nep].[FileRequest].[RequestId]
GROUP BY [nep].[FileRequestStatus].[RequestId], [nep].[FileRequest].[FileName]
HAVING COUNT([nep].[FileRequestStatus].[RequestStatus]) < 2