How to join SELECT statements within a CASE statement to outer queries? - sql

In the following I need to somehow join the fields within the case statement with the outer tables so that the fldNumb is selected for the current PK and CIA values. I am really stuck, can anyone help?
INSERT INTO #CTE (sMedNum)
SELECT T1.sMedNum
FROM #CTE INNER JOIN
(SELECT
(CASE WHEN (Charindex('.', CAST(rInd AS NVARCHAR(30))) > 0)
THEN CAST(( SELECT fldNumb
FROM #CTE
WHERE sCtr = FLOOR(rInd)) AS FLOAT) +
CAST(( SELECT fldNumb
FROM #CTE
WHERE Ind = FLOOR(rInd+1)) AS FLOAT) / 2
ELSE CAST(( SELECT fldNumb
FROM #CTE
WHERE sCtr = rInd) AS FLOAT)
END) AS sMedNum, fldPK, fldCIA
) T1
ON
#CTE.fldPK = T2.fldPK AND
#CTE.fldCIA = T2.fldCIA

Not having your database I cannot help you terribly much, but it looks like you need to be aliasing your tables. If you are trying to get a value from a table outside a subquery, you have to call it something different.
here is an example
select case
when a1.value = 1 then (select a2.id from tableA a2 where a1.val2 = a2.val2)
when a1.value = 2 then (select a3.id from tableA a3 where a1.val2 = a3.val2)
when a1.value = 3 then (select a4.id from tableA a4 where a1.val2 = a4.val2)
end as new_id
from tableA a1
hope this makes sense, if it doesn't, then that is what questions are for ;)

Related

What is a better alternative to procedural approach to produce a string based on columns?

I am working on making string based on column values. Example:
SELECT #Registered = a.hasRegistered
,#Subscribed = a.hasSubscribed
FROM AuthorData a
WHERE a.authorId = 10 --#AUTHORID
IF (#Registered = 1)
SET #ReturnString = #ReturnString + '0,'
IF (#Subscribed = 1)
SET #ReturnString = #ReturnString + '1,'
IF EXISTS (
SELECT TOP 1 name
FROM AUTHORDATA AS A
INNER JOIN AUHTORPROFILE B on A.AUTHORID=B.AUTHORID
INNER JOIN AUTHORHISTORY C ON B.AUTHORPROFILEID=C.AUTHORPROFILEID
WHERE ISNULL(AUTHORDATA.authorId, 0) = 10 --#AUTHORID
)
BEGIN
SET #ReturnString = #ReturnString + '10,'
END
select CONVERT(NVARCHAR(50), STUFF(#ReturnString, LEN(#ReturnString), 1, ''))
This performs the calculation for 1 author (based on WHERE clause IN 2 places -> authorId=10)
I can make this into a function and then call from a select query as follows:
SELECT *,FN_CALCUALTE_OPTIONS(AUTHORID)
FROM AUTHORDATA
I want to ask if there is any way so I can do the calculations in the above SELECT query rather than create the function?
I have tried:
SELECT *,CASE WHEN A.hasRegistered=1 THEN '0,' ELSE '' END +
CASE WHEN A.hasSubscribed=1 THEN '1,' ELSE '' END
FROM AUTHORDATA as A
How can I have the exists part of select?
Pretty sure you can put them all together into a single query as follows. If you didn't need the final stuff you would just have a regular query, but because you need to use the results twice in the stuff CROSS APPLY is a convenient way to calculate it once and use it twice. Also you can correlate your sub-query since you are using the same AuthorData record.
SELECT CONVERT(NVARCHAR(50), STUFF(X.ReturnString, LEN(X.ReturnString), 1, ''))
FROM AuthorData a
CROSS APPLY (
VALUES
(
CASE WHEN a.hasRegistered = 1 THEN '0,' ELSE '' END
+ CASE WHEN a.hasSubscribed = 1 THEN '1,' ELSE '' END
+ CASE WHEN EXISTS (
SELECT 1
FROM AUHTORPROFILE B
INNER JOIN AUTHORHISTORY C ON B.AUTHORPROFILEID = C.AUTHORPROFILEID
WHERE B.AUTHORID = a.AuthorId
)
THEN '10,' else '' end
)
) AS X (ReturnString)
WHERE a.AuthorId = 10 --#AUTHORID
The easiest way IMO is to move your criteria being found via EXISTS to an OUTER APPLY. Like so:
SELECT
CONVERT(NVARCHAR(50), STUFF(calc.ReturnString, LEN(calc.ReturnString), 1, ''))
FROM
AUTHORDATA AS A
OUTER APPLY (SELECT TOP (1)
1 AS Found
FROM
AUHTORPROFILE AS B
INNER JOIN AUTHORHISTORY AS C ON B.AUTHORPROFILEID = C.AUTHORPROFILEID
WHERE
B.authorId = A.authorId) AS lookup_author
/*outer apply here just for readibility in final select*/
OUTER APPLY (SELECT
CONCAT(CASE WHEN A.hasRegistered = 1 THEN '0,' ELSE '' END
,CASE WHEN A.hasRegistered = 1 THEN '1,' ELSE '' END
,CASE WHEN lookup_author.Found = 1 THEN '10,' ELSE '' END) AS ReturnString) AS calc;
Then you can use lookup_author.Found = 1 to determine that it was found in your lookup. From there, you just have to apply the rest of your conditions correctly via CASE statements and then use your final SELECT over the result.
You can put a single CASE statement and get data as given below. Make sure that you are covering every possible condition.
SELECT *, CASE WHEN a.Registered =1 AND a.Subscribed =1
AND EXISTS (SELECT TOP 1 1
FROM AUHTORPROFILE B on
INNER JOIN AUTHORHISTORY C ON B.AUTHORPROFILEID=C.AUTHORPROFILEID
WHERE B.AUTHORID =A.AUTHORID) THEN '0,1,10'
WHEN a.Registered =1 AND a.Subscribed =0
AND EXISTS (SELECT TOP 1 1
FROM AUHTORPROFILE B on
INNER JOIN AUTHORHISTORY C ON B.AUTHORPROFILEID=C.AUTHORPROFILEID
WHERE B.AUTHORID =A.AUTHORID) THEN '0,10'
WHEN a.Registered =0 AND a.Subscribed =1
AND EXISTS (SELECT TOP 1 1
FROM AUHTORPROFILE B on
INNER JOIN AUTHORHISTORY C ON B.AUTHORPROFILEID=C.AUTHORPROFILEID
WHERE B.AUTHORID =A.AUTHORID) THEN '1,10'
WHEN a.Registered =0 AND a.Subscribed =0
AND EXISTS (SELECT TOP 1 1
FROM AUHTORPROFILE B on
INNER JOIN AUTHORHISTORY C ON B.AUTHORPROFILEID=C.AUTHORPROFILEID
WHERE B.AUTHORID =A.AUTHORID) THEN '10'
END AS CalculateOptions
FROM AUTHORDATA AS a

Need to improve the performance of a SQL query

I am new to SQL and I'm facing some problem with the performance of a SQL query.
I followed some points from Google and created the required indexes. But still not able to improve the performance.
Guide me to improve the performance of following the query. The tables have millions of records.
SELECT TOP 15 id,
field1,
field2
FROM (SELECT DISTINCT 0 AS ID,
tblsuites.suite Field1,
'Work Order' AS Field2
FROM tbljb_schedules
INNER JOIN tblsuites
ON tbljb_schedules.tblsuites_id = tblsuites.tblsuites_id
INNER JOIN tblsites
ON tbljb_schedules.tblsites_id = tblsites.tblsites_id
LEFT OUTER JOIN tblbldgs
ON
tbljb_schedules.tblbldgs_id = tblbldgs.tblbldgs_id
WHERE tbljb_schedules.tbldomains_id = 28
AND tbljb_schedules.internalonly = 0
AND tbljb_schedules.tblsites_id IN (SELECT tblsites_id
FROM tbllogins_sites
WHERE tbllogins_id = 264
AND
tblsites.active = 1)
AND ( tblsuites.suite LIKE '%1%' )
UNION
SELECT DISTINCT 0 AS ID,
tblsuites.suite Field1,
'Work Order' AS Field2
FROM arcjb_schedules
INNER JOIN tblsuites
ON arcjb_schedules.tblsuites_id = tblsuites.tblsuites_id
INNER JOIN tblsites
ON arcjb_schedules.tblsites_id = tblsites.tblsites_id
LEFT OUTER JOIN tblbldgs
ON arcjb_schedules.tblbldgs_id =
tblbldgs. tblbldgs_id
WHERE arcjb_schedules.tbldomains_id = 28
AND arcjb_schedules.internalonly = 0
AND arcjb_schedules.tblsites_id IN (SELECT tblsites_id
FROM tbllogins_sites
WHERE tbllogins_id = 264
AND
tblsites.active = 1)
AND ( tblsuites.suite LIKE '%1%' )) T
ORDER BY CASE
WHEN Charindex('1', field1) = 1 THEN 0
ELSE 1
END,
field1
Maybe you should Try the below code changes
SELECT TOP 15
id,
field1,
field2
FROM
(
SELECT
0 AS ID,
tblsuites.suite Field1,
'Work Order' AS Field2,
SeqOne = CASE WHEN CHARINDEX('1', tblsuites.suite)= 1
THEN 1
ELSE 0 END
FROM tbljb_schedules
INNER JOIN tblsuites
ON tbljb_schedules.tblsuites_id = tblsuites.tblsuites_id
INNER JOIN tblsites
ON tbljb_schedules.tblsites_id = tblsites.tblsites_id
LEFT OUTER JOIN tblbldgs
ON tbljb_schedules.tblbldgs_id = tblbldgs.tblbldgs_id
WHERE tbljb_schedules.tbldomains_id = 28
AND tbljb_schedules.internalonly = 0
AND EXISTS -- Replace IN With EXISTS
(
SELECT
1
FROM tbllogins_sites
WHERE tbllogins_id = 264
AND tblsites.active = 1
AND tblsites_id = tbljb_schedules.tblsites_id
)
AND (tblsuites.suite LIKE '%1%')
UNION -- UNION Will By Default Take DISTINCT Records
SELECT
0 AS ID,
tblsuites.suite Field1,
'Work Order' AS Field2,
SeqOne = CASE WHEN CHARINDEX('1', tblsuites.suite)= 1
THEN 1
ELSE 0 END
FROM arcjb_schedules
INNER JOIN tblsuites ON arcjb_schedules.tblsuites_id = tblsuites.tblsuites_id
INNER JOIN tblsites ON arcjb_schedules.tblsites_id = tblsites.tblsites_id
LEFT OUTER JOIN tblbldgs ON arcjb_schedules.tblbldgs_id = tblbldgs.tblbldgs_id
WHERE arcjb_schedules.tbldomains_id = 28
AND arcjb_schedules.internalonly = 0
AND EXISTS
(
SELECT
1
FROM tbllogins_sites
WHERE tbllogins_id = 264
AND tblsites.active = 1
AND tblsites_id = arcjb_schedules.tblsites_id
)
AND (tblsuites.suite LIKE '%1%')
)T
ORDER BY
SeqOne,
field1;
Performance tuning is a more of a trial and error subject.
Looking at your code I can see a major performance offender. This condition in the where clause:
and tblsuites.suite LIKE '%1%'
I don't know how big is the tblSuites table but the use of LIKE '%1%' makes the optimizer perform table scans rather than index seek, so even if you have indexed that column it will be useless.
also follow what #Jayasurya Satheesh mentioned in his answer.

Running slow with intersect

Trying to optimize a query it is updaing the records in table A based on the INTERSECT on two data sets.
UPDATE #TableA
SET IsFlag = CASE WHEN ISNULL(RJobFlag, 0) > 0 THEN 0 ELSE 1 END
FROM #TableA AS ABC
OUTER APPLY (
SELECT 1 RJobFlag
WHERE EXISTS (
SELECT ABC.COLUMN1,ABC.COLUMN2,ABC.COLUMN3,ABC.COLUMN4,ABC.COLUMN5,ABC.COLUMN6,ABC.COLUMN7,ABC.COLUMN8,ABC.COLUMN8,ABC.COLUMN9,ABC.COLUMN10,StudentID,SubjectID
INTERSECT
SELECT XYZ.COLUMN1,XYZ.COLUMN2,XYZ.COLUMN3,XYZ.COLUMN4,XYZ.COLUMN5,XYZ.COLUMN6,XYZ.COLUMN7,XYZ.COLUMN8,XYZ.COLUMN8,XYZ.COLUMN9,XYZ.COLUMN10,StudentID,SubjectID
FROM #TableB AS XYZ
WHERE XYZ.COLUMN1 = (SELECT DISTINCT ID FROM #TableC MNOP WHERE MNOP.StudentID = ABC.StudentID)
AND StudentID = ABC.StudentID
AND SubjectID = ABC.SubjectID )
) Subquery
WHERE ABC.COLUMN1= '2'
Appretiated if you have some ideas to better optimize it.
Thanks
This might be worse never know.
UPDATE tA
SET IsFlag = COALESCE(RJobFlag, 0)
FROM #TableA tA
LEFT JOIN ( SELECT 1 RJobFlag, *
FROM #TableB tB
WHERE EXISTS ( SELECT *
FROM #TableC tC
WHERE tC.ID = tB.COLUMN1 AND tC.StudentID = tB.StudentID)
) tB
ON tA.StudentID = tB.StudentID
AND tA.SubjectID = tB.SubjectID
AND tA.COLUMN1 = tB.COLUMN1
AND tA.COLUMN2 = tB.COLUMN2
AND tA.COLUMN3 = tB.COLUMN3
AND tA.COLUMN4 = tB.COLUMN4
AND tA.COLUMN5 = tB.COLUMN5
AND tA.COLUMN6 = tB.COLUMN6
AND tA.COLUMN7 = tB.COLUMN7
AND tA.COLUMN8 = tB.COLUMN8
AND tA.COLUMN9 = tB.COLUMN9
AND tA.COLUMN10 = tB.COLUMN10
If #TableA has a bunch of records and you're using outer apply or outer join every time you update it will be slow since it has to update every single record. maybe there's a way to only update the records that have changed?

How do I optimize this sql query that takes forever?

I'm trying to optimize this query as it takes 30 seconds to execute:
SELECT
TOP 100 table1.*
FROM
table1 (NOLOCK)
INNER JOIN
DB1..table2 (NOLOCK)
ON DB1..table2.id = DB1..table1.id
INNER JOIN
DB1..table2_batch (NOLOCK)
ON DB1..table2_batch.table2_batch_id = DB1..table2.table2_batch_id
INNER JOIN
DB2..table4 (NOLOCK)
ON CASE
WHEN CHARINDEX(':',
table2_batch.reference_number,
3) > 3 THEN SUBSTRING(table2_batch.reference_number,
3,
CHARINDEX(':',
table2_batch.reference_number,
3) -3 )
ELSE
RIGHT(table2_batch.reference_number,
LEN(table2_batch.reference_number) -2)
end = Cast(table4.PurchaseOrderID as int) INNER JOIN
DB2..table3 (NOLOCK)
ON DB2..table3.key = DB2..table4.key
WHERE
table1.id IS NOT NULL
AND (
table1.id!=''
OR table1.id IS NULL
)
AND DB2..table3.AccountTypeID != 30000
AND CHARINDEX('O', DB1..table2_batch.reference_number) = 1
AND table1_id NOT IN (
select
lim.table1_id
from
link_table1_message as lim (nolock)
inner join
table1 as i (nolock)
on i.table1_id = lim.table1_id
where
lim.message_id >= 90
)
ORDER BY
last_hit DESC
Based on this comment:
The bottleneck is on the DB2..table4 join. When I take that part out it does the query really fast ... but I really need that join in there to make sure the proper condition is met for this scenario.
It's a little bit of a guess because we don't know how many rows are involved, nor what your schema looks like, but making a few assumptions, this could possibly help:
INNER JOIN
DB2..table4 (NOLOCK)
ON CASE
WHEN CHARINDEX(':',
table2_batch.reference_number,
3) > 3 THEN SUBSTRING(table2_batch.reference_number,
3,
CHARINDEX(':',
table2_batch.reference_number,
3) -3 )
ELSE
RIGHT(table2_batch.reference_number,
LEN(table2_batch.reference_number) -2)
end = Cast(table4.PurchaseOrderID as int)
That's a lot of logic to put in a join I find.
You have table2_batch that has a reference_number that's encoding a value that you'll end up needing to extract and use to join with table4.PurchaseOrderID; I'd start by selecting that first:
with cteTable2 as (
select
table2_batch_id
,reference_number
,case when charindex(':',reference_number,3) > 3
then substring(reference_number,3,charindex(':',reference_number,3) - 3)
else right(reference_number,len(reference_number) - 2)
end PurchaseOrderID
from table2_batch
)
And then you can treat cteTable2 as a full-fledged table in the select statement that follows, so instead of joining with table2_batch, you join with cteTable2:
inner join DB2..table4 (NOLOCK)
on cteTable2.PurchaseOrderID = cast(table4.PurchaseOrderID as int)
...and is that cast really needed?

Consolidating results on one row SQL

I would like to consolidate a one to many relationship that outputs on different rows to a single row.
(select rate_value1
FROM xgenca_enquiry_event
INNER JOIN xgenca_enquiry_iso_code_translation
ON
xgenca_enquiry_event_rate.rate_code_id
= xgenca_enquiry_iso_code_translation.id
where xgenca_enquiry_event_rate.event_id = xgenca_enquiry_event.id
and ISO_code = 'PDIV') as PDIVrate,
(select rate_value1
FROM xgenca_enquiry_event
INNER JOIN xgenca_enquiry_iso_code_translation
ON
xgenca_enquiry_event_rate.rate_code_id
= xgenca_enquiry_iso_code_translation.id
where xgenca_enquiry_event_rate.event_id = xgenca_enquiry_event.id
and ISO_code = 'TAXR') as TAXrate
PDIVrate TAXrate
NULL 10.0000000
0.0059120 NULL
I would like the results on one row. Any help would be greatly appreciated.
Thanks.
You can use an aggregate function to perform this:
select
max(case when ISO_code = 'PDIV' then rate_value1 end) PDIVRate,
max(case when ISO_code = 'TAXR' then rate_value1 end) TAXRate
FROM xgenca_enquiry_event_rate r
INNER JOIN xgenca_enquiry_iso_code_translation t
ON r.rate_code_id = t.id
INNER JOIN xgenca_enquiry_event e
ON r.event_id = e.id
It looks like you are joining three tables are are identical in the queries. This consolidates this into a single query using joins.
Look here:
Can I Comma Delimit Multiple Rows Into One Column?
Simulate Oracle's LISTAGG() in SQL Server using STUFF:
SELECT Column1,
stuff((
SELECT ', ' + Column2
FROM tableName as t1
where t1.Column1 = t2.Column1
FOR XML PATH('')
), 1, 2, '')
FROM tableName as t2
GROUP BY Column1
/
Copied from here: https://github.com/jOOQ/jOOQ/issues/1277