In a nested query, check all values for a condition - sql

How can I get rid of nested queries (agree, dis_agreed)? How to rewrite to join - I can not think of it. Maybe there are other optimal solutions?
select *
from (
select
(select count(id) from Agreement a where a.ConclusionCardFile = f.id and a.Status = 1) agreed,
(select count(id) from Agreement a where a.ConclusionCardFile = f.id and (a.Status <> 1 or a.Status is null)) dis_agreed
from ConclusionCard_Files f
) t
where t.agreed > 0 and dis_agreed = 0

You can write the conditions as a where clause:
select *
from conclusionCard_Files
where exists (
select *
from agreement
where agreement.conclusionCardFile = conclusionCard_Files.id
having sum(case when status = 1 then 1 else 0 end) > 0
and sum(case when status = 1 then 0 else 1 end) = 0
)

Maybe you just using sub-queries only to filter? What about to move them to WHERE clause?
SELECT
*
FROM ConclusionCard_Files f
WHERE
EXISTS(select * from Agreement a where (a.ConclusionCardFile = f.id) and a.Status =1)
AND NOT EXISTS(select * from Agreement a where (a.ConclusionCardFile = f.id) and (a.Status != 1 or a.Status is null))
It's performance friendly because SqlServer do not count all Counts

If I understand correctly, you can try to use JOIN with HAVING condition aggregate function.
SELECT COUNT(CASE WHEN a.Status = 1 THEN ID END) agreed,
COUNT(CASE WHEN a.Status <> 1 or a.Status is null THEN ID END) dis_agreed
FROM Agreement a
INNER JOIN ConclusionCard_Files f
ON a.ConclusionCardFile = f.id
HAVING
COUNT(CASE WHEN a.Status = 1 THEN ID END) > 0
AND
COUNT(CASE WHEN a.Status <> 1 or a.Status is null THEN ID END) = 0
EDIT
if you want to get data from ConclusionCard_Files based on your condition. you can try to let condition aggregate function in subquery each ConclusionCardFile from table Agreement then do JOIN
SELECT f.*
FROM (
SELECT COUNT(CASE WHEN a.Status = 1 THEN ID END) agreed,
COUNT(CASE WHEN a.Status <> 1 or a.Status is null THEN ID END) dis_agreed,
a.ConclusionCardFile
FROM Agreement a
GROUP BY a.ConclusionCardFile
) a
INNER JOIN ConclusionCard_Files f
ON a.ConclusionCardFile = f.id
WHERE a.agreed > 0 AND a.dis_agreed = 0

Related

SELECT statement with operators not working

I have these two tables and I need a query, that outputs every member that has the lvnr 050056 AND NOT 050054.
I have these two tables
I have tried it with the following query but it does not work right:
SELECT s.matrnr, s.vorname, s.nachname
FROM student s
INNER JOIN teilgenommen t ON s.matrnr = t.matrnr
WHERE (t.lvnr = 050056) AND (t.lvnr != 050054)
Only Martin Huber with the ID 0111111 should be shown, but I get both..
I would be very thankful for any advie
Use exists and not exists:
select s.*
from student s
where exists (select 1
from teilgenommen t
where t.matrnr = s.matrnr and t.lvnr = '050056'
) and
not exists (select 1
from teilgenommen t
where t.matrnr = s.matrnr and t.lvnr = '050054'
);
The leading zeros suggest that lvnr is really stored as a string. If so, then single quotes should be used for the comparison value.
You can do:
SELECT
s.matrnr,
s.vorname,
s.nachname
FROM
student s
INNER JOIN
(
select
matrnr,
max(case when lvnr='050056' then 1 else 0 end) as a,
max(case when lvnr='050054' then 1 else 0 end) as b
from
teilgenommen
group by
matrnr
having a=1 and b=0
) t
ON s.matrnr = t.matrnr
This can also be solved with aggregation and a having clause for filtering:
select s.matrnr, s.vorname, s.nachname
from student s
inner join teilgenommen t on s.matrnr = t.matrnr
group by s.matrnr, s.vorname, s.nachname
having
max(case when t.lvnr = 050056 then 1 else 0 end) = 1
and max(case when t.lvnr = 050054 then 1 else 0 end) = 0

Using sub query in in group by sql server

Hello everyone I would like to use sub query as code bellow but it get error I would like to to ask you that I how can i do this. Thanks!
SELECT HR_EMPMAST.DEPT,HR_DEPARTMENT.DESCRIPTION AS DEPARTMENT,HR_JOBFUNCTION.CODE,HR_JOBFUNCTION.DESCRIPTION AS POSITION,
COUNT(HR_EMPMAST.EMPCODE) ACTUAL,
SUM(CASE WHEN HR_EMPMAST.SEX = 'M' THEN 1 ELSE 0 END) AS M,
SUM(CASE WHEN HR_EMPMAST.SEX = 'F' THEN 1 ELSE 0 END) AS F,SUM(CASE WHEN HR_EMPMAST.EMPTYPE='LOCAL' THEN 1 ELSE 0 END) AS LOCALEMP,
SUM(CASE WHEN HR_EMPMAST.EMPTYPE='EXPAT' THEN 1 ELSE 0 END) AS EXPATEMP--,
(SELECT EMPNO FROM HR_HEADCOUNT WHERE POSITION=HR_EMPMAST.JOBCODE AND INMONTH=1 AND INYEAR=2017) AS EMPNO
FROM HR_EMPMAST
LEFT JOIN HR_DEPARTMENT
ON HR_EMPMAST.DEPT = HR_DEPARTMENT.CODE
LEFT JOIN HR_JOBFUNCTION
ON HR_EMPMAST.JOBCODE=HR_JOBFUNCTION.CODE
WHERE HR_EMPMAST.CAREERDESC <> 'TERMIMATE'
GROUP BY HR_EMPMAST.DEPT,HR_DEPARTMENT.DESCRIPTION,HR_JOBFUNCTION.CODE,HR_JOBFUNCTION.DESCRIPTION
At first, please, use table aliases.
Second: you need to add ALL columns from SELECT to GROUP BY (but not ones in SUM and COUNT functions).
Third: you got strange EMPNO select. Maybe better way is to use JOIN?
Try to use this one:
SELECT e.DEPT,
d.DESCRIPTION AS DEPARTMENT,
jf.CODE,
jf.DESCRIPTION AS POSITION,
COUNT(e.EMPCODE) ACTUAL,
SUM(CASE WHEN e.SEX = 'M' THEN 1 ELSE 0 END) AS M,
SUM(CASE WHEN e.SEX = 'F' THEN 1 ELSE 0 END) AS F,
SUM(CASE WHEN e.EMPTYPE='LOCAL' THEN 1 ELSE 0 END) AS LOCALEMP,
SUM(CASE WHEN e.EMPTYPE='EXPAT' THEN 1 ELSE 0 END) AS EXPATEMP,
hc.EMPNO
FROM HR_EMPMAST e
LEFT JOIN HR_DEPARTMENT d
ON e.DEPT = d.CODE
LEFT JOIN HR_JOBFUNCTION jf
ON e.JOBCODE = jf.CODE
LEFT JOIN HR_HEADCOUNT hc
ON hc.POSITION = e.JOBCODE AND hc.INMONTH=1 AND hc.INYEAR=2017
WHERE e.CAREERDESC <> 'TERMIMATE'
GROUP BY e.DEPT,
d.DESCRIPTION,
jf.CODE,
jf.DESCRIPTION,
hc.EMPNO
Try this below query or include HR_EMPMAST.JOBCODE in group by clause...
SELECT HR_EMPMAST.DEPT,HR_DEPARTMENT.DESCRIPTION AS DEPARTMENT,HR_JOBFUNCTION.CODE,HR_JOBFUNCTION.DESCRIPTION AS POSITION,
COUNT(HR_EMPMAST.EMPCODE) ACTUAL,
SUM(CASE WHEN HR_EMPMAST.SEX = 'M' THEN 1 ELSE 0 END) AS M,
SUM(CASE WHEN HR_EMPMAST.SEX = 'F' THEN 1 ELSE 0 END) AS F,SUM(CASE WHEN HR_EMPMAST.EMPTYPE='LOCAL' THEN 1 ELSE 0 END) AS LOCALEMP,
SUM(CASE WHEN HR_EMPMAST.EMPTYPE='EXPAT' THEN 1 ELSE 0 END) AS EXPATEMP,
em.EMPNO AS EMPNO
FROM HR_EMPMAST
LEFT JOIN (SELECT POSITION, EMPNO FROM HR_HEADCOUNT WHERE INMONTH=1 AND INYEAR=2017) em on em.POSITION=HR_EMPMAST.JOBCODE
LEFT JOIN HR_DEPARTMENT
ON HR_EMPMAST.DEPT = HR_DEPARTMENT.CODE
LEFT JOIN HR_JOBFUNCTION
ON HR_EMPMAST.JOBCODE=HR_JOBFUNCTION.CODE
WHERE HR_EMPMAST.CAREERDESC <> 'TERMIMATE'
GROUP BY HR_EMPMAST.DEPT,HR_DEPARTMENT.DESCRIPTION,HR_JOBFUNCTION.CODE,HR_JOBFUNCTION.DESCRIPTION

SQL Server Converting Rows to Columns

I am currently extracting data using 3 different tables, and below is the output.
Current Result:
Query Used:
SELECT
dbo.TableB.TrackingID, dbo.TableA.FinancialID,
dbo.TableA.ParcelCode, dbo.TableA.TotalAmount,
dbo.TableB.FinanceType, dbo.TableB.TransactionType,
dbo.TableC.CustID
FROM
dbo.TableA
INNER JOIN
dbo.TableB ON dbo.TableA.FinancialID = dbo.TableB.FinancialID
INNER JOIN
dbo.TableC ON dbo.TableB.TrackingID = dbo.TableC.TrackingID
WHERE
(dbo.TableB.TrackingID = '17006218AU')
I would like to have the following output:
Desired Output:
You can get the output you desire with grouping and some CASE statements inside SUM aggregate functions:
SELECT
dbo.TableB.TrackingID,
dbo.TableA.ParcelCode,
dbo.TableC.CustID,
SUM(CASE WHEN dbo.TableB.FinanceType = 'Invoice' THEN dbo.TableA.TotalAmount ELSE 0 END) AS TotalAmount,
SUM(CASE WHEN dbo.TableB.FinanceType = 'Invoice' AND TransType='Card' THEN dbo.TableA.TotalAmount ELSE 0 END) AS CardInvoice,
SUM(CASE WHEN dbo.TableB.FinanceType = 'Invoice' AND TransType='Cash' THEN dbo.TableA.TotalAmount ELSE 0 END) AS CashInvoice,
SUM(CASE WHEN dbo.TableB.FinanceType = 'PaymentRecepit' THEN dbo.TableA.TotalAmount ELSE 0 END) AS CardPaymentRecepit
FROM dbo.TableA
INNER JOIN dbo.TableB ON dbo.TableA.FinancialID = dbo.TableB.FinancialID
INNER JOIN dbo.TableC ON dbo.TableB.TrackingID = dbo.TableC.TrackingID
WHERE
dbo.TableB.TrackingID = '17006218AU'
GROUP BY
dbo.TableB.TrackingID,
dbo.TableA.ParcelCode,
dbo.TableC.CustID

How can I add a sub-query to this cursor?

I tried to add a sub query (StoCount) to the following cursor:
DECLARE trans_cur CURSOR FOR
SELECT b.TransportNumber,
SUM(CASE WHEN a.DeliveryItemStatus = 'C' OR a.DeliveryItemStatus = 'V' THEN 1 ELSE 0 END) AS Completed,
COUNT(*) AS Total,
SUM(CASE WHEN a.DeliveryItemStatus = 'F' THEN 1 ELSE 0 END) AS Missing,
(SELECT COUNT(*) FROM StorageTransportOrderItem WHERE DeliveryNumber = a.DeliveryNumber AND DeliveryItemNumber = a.DeliveryItemNumber) As StoCount
FROM DeliveryItem a
INNER JOIN TransportItem b on a.DeliveryNumber = b.DeliveryNumber
INNER JOIN Material c on a.MaterialNumber = c.MaterialNumber
INNER JOIN Transport d on b.TransportNumber = d.TransportNumber
WHERE a.StorageLocationNumber IS NOT NULL
AND a.Deleted <> 1
AND c.CommissioningArea LIKE #commissioningArea
AND d.TransportStatus < 70
GROUP BY b.TransportNumber
but when I always get the error message:
Msg 8120, Level 16, State 1, Procedure sp_CalculateTransportProgress,
Line 41 Column 'DeliveryItem.DeliveryNumber' is invalid in the select
list because it is not contained in either an aggregate function or
the GROUP BY clause. Msg 8120, Level 16, State 1, Procedure
sp_CalculateTransportProgress, Line 41 Column
'DeliveryItem.DeliveryItemNumber' is invalid in the select list
because it is not contained in either an aggregate function or the
GROUP BY clause.
My goal is to add this single column (StoCount) to the cursor without modifying the query too much.
Is that possible?
You could move the correlated subquery to a cross apply
SELECT b.TransportNumber,
SUM(CASE WHEN a.DeliveryItemStatus = 'C' OR a.DeliveryItemStatus = 'V' THEN 1 ELSE 0 END) AS Completed,
COUNT(*) AS Total,
SUM(CASE WHEN a.DeliveryItemStatus = 'F' THEN 1 ELSE 0 END) AS Missing,
MAX(e.Freq) AS StoCount
FROM DeliveryItem a
INNER JOIN TransportItem b on a.DeliveryNumber = b.DeliveryNumber
INNER JOIN Material c on a.MaterialNumber = c.MaterialNumber
INNER JOIN Transport d on b.TransportNumber = d.TransportNumber
CROSS APPLY (
SELECT COUNT(*) freq FROM StorageTransportOrderItem s
WHERE s.DeliveryNumber = a.DeliveryNumber AND s.DeliveryItemNumber = a.DeliveryItemNumber
) e
WHERE a.StorageLocationNumber IS NOT NULL
AND a.Deleted <> 1
AND c.CommissioningArea LIKE #commissioningArea
AND d.TransportStatus < 70
GROUP BY b.TransportNumber
Edit by xsl:
I had to modify the query a bit, so that it returned the correct results for my database:
SELECT b.TransportNumber,
SUM(CASE WHEN a.DeliveryItemStatus = 'C' OR a.DeliveryItemStatus = 'V' THEN 1 ELSE 0 END) AS Completed,
COUNT(*) AS Total,
SUM(CASE WHEN a.DeliveryItemStatus = 'F' THEN 1 ELSE 0 END) AS Missing,
SUM(e.Freq) AS StoCount
FROM DeliveryItem a
INNER JOIN TransportItem b on a.DeliveryNumber = b.DeliveryNumber
INNER JOIN Material c on a.MaterialNumber = c.MaterialNumber
INNER JOIN Transport d on b.TransportNumber = d.TransportNumber
CROSS APPLY (
SELECT COUNT(1) freq FROM StorageTransportOrderItem s
WHERE
s.DeliveryNumber = a.DeliveryNumber
AND s.DeliveryItemNumber = a.DeliveryItemNumber
AND s.MaterialNumber = a.MaterialNumber
) e
WHERE a.StorageLocationNumber IS NOT NULL
AND a.Deleted <> 1
AND c.CommissioningArea LIKE #commissioningArea
AND d.TransportStatus < 70
GROUP BY b.TransportNumber

How to add 2 numbers in sql Select clause?

I have this query:
Select
Count(DocumentID)
From
Documents d
Inner Join
Accounts a on a.AccountID = d.CreatedByAccountID
Where
a.FeeExempt = 1
Or
(Select
Case
When a.OrganizationTypeID = 1 Or a.OrganizationTypeID = 2
Then 0
Else EFileFee
End
From ITypes
Where ITypeID = d.ITypeID
+
Select 100 --just to test
) <= 0
How can I make this query compile? Basically I want to do 2 selects and check if addition of both of them is less than 0 or not. But obviously at the moment the query is incorrect and won't compile.
Do you want this:
. . ..
(select sum(val)
from ((Select (Case When a.OrganizationTypeID = 1 Or a.OrganizationTypeID = 2 Then 0 Else EFileFee End) as val
From ITypes
Where ITypeID = d.ITypeID
) union all
(Select 100 --just to test
)
) t
) <= 0