Optimize Nested Select query - sql-server

How to optimize the following query to be work better :
SELECT c.a1,c.a2,
(SELECT SUM(t2.TempOB) FROM tbl1 t2 WHERE t2.AccNo LIKE CONCAT( C.AccNo,'%') )OB,
(SELECT SUM(t3.TempDebit) FROM tbl1 t3 WHERE t3.AccNo LIKE CONCAT( C.AccNo,'%') ) Debit,
(SELECT SUM(t4.TempCredit) FROM tbl1 t4 WHERE t4.AccNo LIKE CONCAT( C.AccNo,'%') ) Credit
FROM tbl1 C WHERE AccLevel= #Level

You can use as the below:
SELECT
A.a1,
A.a2,
SUM(B.OB) AS OB,
SUM(B.Debit) AS Debit,
SUM(B.Credit) AS Credit
FROM
tbl1 A LEFT JOIN
tbl1 B ON B.AccNo LIKE A.AccNo + '%'
WHERE
A.AccLevel = #Level
GROUP BY
A.a1,
A.a2

Related

When joining tables adapt the "on" statement depending on the query results

I have 2 tables:
Table_1 with columns col_A, col_B , col_C , col_D , col_E
Table_2 with columns col_A, col_B , col_C , col_D , col_F
I would like to join them on columns col_A, col_B , col_C , col_D.
For the rows in Table_1 that do not get joined this way (as they don't have a match in Table_2), I would like to join them only on columns col_A, col_B , col_C.
If there are still rows in Table_1 that did not get joined, i would like to join them only on columns col_A, col_B.
And once that is done and there are still rows in Table_1 that did not get joined, i would like to join them only on column col_A.
I wrote the following script where i use a new table to get this result.
Is there is a more efficient way to do this? Preferably by creating a view, not a table?
create table new_table (col_A nvarchar(50) , col_B nvarchar(50) , col_C nvarchar(50)
, col_D nvarchar(50) , col_E nvarchar(50) , col_F nvarchar(50) )
go
insert into new_table
select Table_1.* , Table_2.col_F
from Table_1
inner join Table_2
on Table_1.col_A=Table_2.col_A
and Table_1.col_B=Table_2.col_B
and Table_1.col_C=Table_2.col_C
and Table_1.col_D=Table_2.col_D
go
insert into new_table
select Table_1.* , Table_2.col_F
from Table_1
inner join Table_2
on Table_1.col_A=Table_2.col_A
and Table_1.col_B=Table_2.col_B
and Table_1.col_C=Table_2.col_C
where concat (Table_1.col_A, Table_1.col_B , Table_1.col_C , Table_1.col_D , Table_1.col_E
not in (select concat (col_A, col_B , col_C , col_D , col_E) from new_table)
go
insert into new_table
select Table_1.* , Table_2.col_F
from Table_1
inner join Table_2
on Table_1.col_A=Table_2.col_A
and Table_1.col_B=Table_2.col_B
where concat (Table_1.col_A, Table_1.col_B , Table_1.col_C , Table_1.col_D , Table_1.col_E
not in (select concat (col_A, col_B , col_C , col_D , col_E) from new_table)
go
insert into new_table
select Table_1.* , Table_2.col_F
from Table_1
inner join Table_2
on Table_1.col_A=Table_2.col_A
where concat (Table_1.col_A, Table_1.col_B , Table_1.col_C , Table_1.col_D , Table_1.col_E
not in (select concat (col_A, col_B , col_C , col_D , col_E) from new_table)
go
You could join them on just colA and then assign some different numbers:
WITH cte AS(
SELECT
CASE WHEN t1.D = t2.D THEN 100 ELSE 0 END +
CASE WHEN t1.C = t2.C THEN 10 ELSE 0 END +
CASE WHEN t1.B = t2.B THEN 1 ELSE 0 END as whatMatched,
*
FROM
t1 JOIN t2 on t1.A = t2.A
)
Now if a row got 111 we know that all (ABCD) matched, got 0 then only A matched etc..
So we can ask for only some rows:
SELECT * FROM cte WHERE whatmatched IN (111,11,1,0)
And lastly if there were multiples (matching on just A might mean there are duplicates), we can assign a row number to them in descending order and only take the first row:
SELECT x.* FROM
(SELECT *, ROW_NUMBER() OVER(ORDER BY whatmatched DESC) rown FROM cte WHERE whatmatched IN (111,11,1,0)) x
WHERE x.rown = 1
If it suits you better to use letters
we can assess the matches, choose only A, AB, ABC, or ABCD, then pick the most specific one by looking at the LENgth of the match string:
WITH cte AS(
SELECT
'A' +
CASE WHEN t1.B = t2.B THEN 'B' ELSE '' END +
CASE WHEN t1.C = t2.C THEN 'C' ELSE '' END +
CASE WHEN t1.D = t2.D THEN 'D' ELSE '' END as whatMatched,
*
FROM
t1 JOIN t2 on t1.A = t2.A
)
SELECT x.* FROM
(SELECT *, ROW_NUMBER() OVER(ORDER BY LEN(whatmatched) DESC) rown FROM cte WHERE whatmatched IN ('A','AB','ABC','ABCD')) x
WHERE x.rown = 1
If you want ties (i.e. a row from t1 that matches two rows from t2 because their A/B/C is the same and D differs, use DENSE_RANK instead of ROW_NUMBER so they end up tied for first place

Select all records when multiple value parameter is blank

I'm creating a report in SSRS and want to have a multiple value parameter but allow blank values (''), and display all records when blank.
The gist of it is:
SELECT *
FROM Products p
JOIN ProductCategories c on c.ProductId = p.Id
WHERE (c.Name IN (#Categories) OR #Categories = '')
Which works when blank, and works with 1 category, but errors out with 2 categories. We got around this by using a temp table, but that solution seemed sort of hacky, so I wanted to see if there was a better way to resolve this.
The temp table workaround we built was this:
CREATE TABLE #temp (ProductId INT, Category NVARCHAR(MAX))
INSERT INTO #temp
SELECT p.Id, c.Name
FROM Products p
JOIN ProductCategories c on c.ProductId = p.Id
WHERE c.Name IN (#Categories)
IF ((SELECT COUNT(*) FROM #temp) = 0)
BEGIN
INSERT INTO #temp
SELECT p.Id, c.Name
FROM Products p
JOIN ProductCategories c on c.ProductId = p.Id
WHERE c.Name LIKE '%'
END
SELECT * FROM #temp
Thanks in advance!
If you don't have a split/parse function
Example
...
Where #Categories = ''
or
C.Name in (
Select RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(#Categories,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
)
Here is a dbFiddle ... You'll notice Poultry was excluded, then try it when #Categories=''

SQL Server: Join tables in a loop going through table rows

I have a table with the following fiels: PicklistTable, PicklistColumnName, FormTable and FormColumnName. FormColumnName is a foreign key into PicklistTable that I need to join on PicklistColumnName. Basically I need to find out how many times each picklist values has been used on all forms that reference that picklist. So the query would look something like this (maybe??):
SELECT PicklistColumnName, count(FormColumnName1) + count(FormColumnName2) as Count
FROM PicklistTable
INNER JOIN FormTable1 ON PicklistColumnName = FormColumnName1
INNER JOIN FormTable2 ON PicklistColumnName = FormColumnName2
GROUP BY PicklistColumnName
Here is an example table:
PicklistTable PicklistColumnName FormTable FormColumnName
tblEthnicityValues Ethnicity_ID tblContact Contact_Ethnicity_ID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACIHAC FatherEthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACIHAC MotherEthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACIHAYP EthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACIHAYP FatherEthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACIHAYP MotherEthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACRHAC FatherEthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACRHAC MotherEthnicityID
So I would in this case need to join tblContact, udfOHFTCYPLACIHAC etc on Contact_Ethnicity_ID, FatherEthnicityID etc.
Can someone please help? I hope I explained it well enough.
Thanks!
Tanya
Assuming that the PicklistColumnName from PicklistTable table need not be present in both FormTable1 and FormTable2 tables, this query might solve your problem.
SELECT pt.PicklistColumnName, count(ft1.FormColumnName1) + count(ft2.FormColumnName2) as Count
FROM PicklistTable pt
LEFT OUTER JOIN FormTable1 ft1
ON pt.PicklistColumnName = ft1.FormColumnName1
LEFT OUTER JOIN FormTable2 ft2
ON pt.PicklistColumnName = ft2.FormColumnName2
GROUP BY pt.PicklistColumnName
Do you want to get the following SQL:
DECLARE #tb TABLE(PicklistTable VARCHAR(30),PicklistColumnName VARCHAR(30),FormTable VARCHAR(30),FormColumnName VARCHAR(30) )
INSERT INTO #tb(PicklistTable,PicklistColumnName,FormTable,FormColumnName)
SELECT 'tblEthnicityValues','Ethnicity_ID','tblContact','Contact_Ethnicity_ID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACIHAC','FatherEthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACIHAC','MotherEthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACIHAYP','EthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACIHAYP','FatherEthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACIHAYP','MotherEthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACRHAC','FatherEthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACRHAC','MotherEthnicityID'
DECLARE #sql VARCHAR(max)
SELECT #sql='SELECT '+t.PicklistColumnName+',(0'+t.subCountSQL+') AS'+CHAR(13)+'Count FROM '+t.PicklistTable+CHAR(13)+t.subSQL FROM (
SELECT DISTINCT PicklistTable,PicklistColumnName,t2.* ,t3.*
FROM #tb AS t1
CROSS APPLY(SELECT 'INNER JOIN '+FormTable+' ON PicklistColumnName='+tt.FormTable+'.'+tt.FormColumnName+' '
FROM #tb AS tt WHERE tt.PicklistTable=t1.PicklistTable AND tt.PicklistColumnName=t1.PicklistColumnName
FOR XML PATH('')
) AS t2(subSQL)
CROSS APPLY(SELECT '+COUNT('+tt.FormTable+'.'+tt.FormColumnName +')'
FROM #tb AS tt WHERE tt.PicklistTable=t1.PicklistTable AND tt.PicklistColumnName=t1.PicklistColumnName
FOR XML PATH('')
) AS t3(subCountSQL)
)AS t
PRINT #sql
EXEC(#SQL)
The variable #SQL will be :
SELECT Ethnicity_ID,(0+COUNT(tblContact.Contact_Ethnicity_ID)+COUNT(udfOHFTCYPLACIHAC.FatherEthnicityID)+COUNT(udfOHFTCYPLACIHAC.MotherEthnicityID)+COUNT(udfOHFTCYPLACIHAYP.EthnicityID)+COUNT(udfOHFTCYPLACIHAYP.FatherEthnicityID)+COUNT(udfOHFTCYPLACIHAYP.MotherEthnicityID)+COUNT(udfOHFTCYPLACRHAC.FatherEthnicityID)+COUNT(udfOHFTCYPLACRHAC.MotherEthnicityID)) AS Count FROM tblEthnicityValues
INNER JOIN tblContact ON PicklistColumnName=tblContact.Contact_Ethnicity_ID INNER JOIN udfOHFTCYPLACIHAC ON PicklistColumnName=udfOHFTCYPLACIHAC.FatherEthnicityID INNER JOIN udfOHFTCYPLACIHAC ON PicklistColumnName=udfOHFTCYPLACIHAC.MotherEthnicityID INNER JOIN udfOHFTCYPLACIHAYP ON PicklistColumnName=udfOHFTCYPLACIHAYP.EthnicityID INNER JOIN udfOHFTCYPLACIHAYP ON PicklistColumnName=udfOHFTCYPLACIHAYP.FatherEthnicityID INNER JOIN udfOHFTCYPLACIHAYP ON PicklistColumnName=udfOHFTCYPLACIHAYP.MotherEthnicityID INNER JOIN udfOHFTCYPLACRHAC ON PicklistColumnName=udfOHFTCYPLACRHAC.FatherEthnicityID INNER JOIN udfOHFTCYPLACRHAC ON PicklistColumnName=udfOHFTCYPLACRHAC.MotherEthnicityID

TSQL Rewrite UNION into JOIN

I'm new to SQL and I'm trying to rewrite this query so that it uses a join instead of a union
DECLARE #user VARCHAR(255) = 'jSmith'
DECLARE #dept VARCHAR(255) = 'produce'
SELECT DISTINCT A.*
FROM goals A
INNER JOIN managers B ON B.name = #user
WHERE #user IN (A.userName,A.managerUserName)
AND dept = #dept
AND yr = '2016'
UNION
SELECT DISTINCT A.*
FROM goals A
INNER JOIN managers C ON C.name = #user
INNER JOIN committedGoals B ON A.goalID = B.goalID
WHERE dept LIKE #dept + '%'
AND yr = '2016'
This is not exactly the same because you've restricted the second part of the query to records that contain a record in committedGoals, but if you always have a record, then this might work for you:
SELECT g.*
FROM goals g
LEFT JOIN managers m
ON g.managerUserName=m.name
WHERE dept LIKE #dept + '%'
AND yr='2016'
AND (g.managerUserName=#user OR m.name=#user)

SQL server Temp table with joins inside other select

I have the following structure:
Create #temp
Select ...inser...into #temp where ...
(select ... from #temp
Join tblA where ... )
UNION
(Select ... from #temp
join tblB where ... )
After build above table I need to be able to perform WHERE, JOINS, ...
Something like:
Select ... from (above statement)
join ....
where....
I don't know how of if a #temp,joins, union... can be inside other select.
OR only thing I can do is create a #Temp2 inserting with first statement result and then work with other join,where... ?
UPDATE 1:
I also trying:
With cte (query returned columns)
as
(same query I was using to build my #temp as before)
(select ... from cte
join tblA
where...)
UNION
(select ... from cte
join tblB
where...)
But Im stuck at same point in how to perform other joins, where... with above total result
Create #temp
Select ...inser...into #temp where ...
;with temp2 as
(
select ... from #temp Join tblA where ...
UNION
Select ... from #temp join tblB where ...
)
select ... from temp2
join ....
where....
Actually you can do it without temp-table:
WITH myCTE [ ( column_name [,...n] ) ]
AS
( here you define your query )
and after that you just do your Select but use CTE
Select ... from myCTE
join ....
where....
about CTE you can read Here
After Update
Select fields from myCTE join table1
Union
Select fields from myCTE join table2
Without brackets in your query

Resources