SQL - Show 2 columns - sql-server

I would like to display a table with the following columns:
SKU
Inventory in WarehouseA
Inventory in WarehouseB
123
10
20
Below is my current query:
select a.ItemID, SUM(a.Quantity), b.WarehouseDescription
from dbo.a
INNER JOIN dbo.b on a.WarehouseID = b.WarehouseID
GROUP BY a.ItemID, b.WarehouseDescription
HAVING a.Quantity <>0
and b.WarehouseDescription = 'WarehouseA'
and b.WarehouseDescription = 'WarehouseB'
ORDER BY a.ItemID, b.WarehouseDescription
The output generated so far follows this form:
 
 
 
SKU
Inventory in WarehouseA
Warehouse A
SKU
Inventory in Warehouse B
Warehouse B
123
10
Warehouse A
123
20
Warehouse B
Feedback/constructive comments are welcome!

Mostly guessing here as we don't have much detail to work with. But something like this is how you might tackle conditional aggregation for this.
select a.ItemID
, WarehouseA = SUM(case when b.WarehouseDescription = 'WarehouseA' then a.Quantity else 0 end)
, WarehouseB = SUM(case when b.WarehouseDescription = 'WarehouseB' then a.Quantity else 0 end)
from dbo.a
INNER JOIN dbo.b on a.WarehouseID = b.WarehouseID
where b.WarehouseDescription in ('WarehouseA', 'WarehouseB')
GROUP BY a.ItemID
HAVING a.Quantity <>0
ORDER BY a.ItemID
, b.WarehouseDescription

Related

T-SQL, repeated same scalar subquery performance in views

Below is a simple query that retrieves Students and their exam results. The same student can take the same exam multiple times. The subqueries retrieve the latest exam results for each student. As you can see, the Line X (which retrieves the latest Exam ID) is exactly the same in every subquery for each row. How to store or cache the result of Line X to prevent three times execution for each row?
I cannot use stored procedure or functions for this task, it has to be a VIEW for additional filtering.
SELECT S.*,
(
SELECT COUNT(*) FROM ExamAnswers WHERE
IsCorrectAnswer IS NOT NULL AND
IsCorrectAnswer = 1 AND
ExamID =
(SELECT TOP(1) ID FROM Exams E WHERE E.StudentID = S.ID ORDER BY ID DESC) --Line X
) CorrectAnswerCount,
(
SELECT COUNT(*) FROM ExamAnswers EA WHERE
EA.IsCorrectAnswer IS NOT NULL AND
EA.IsCorrectAnswer = 0 AND
EA.ExamID =
(SELECT TOP(1) ID FROM Exams E WHERE E.StudentID = S.ID ORDER BY ID DESC) --Line X
) WrongAnswerCount,
(
SELECT COUNT(*) FROM ExamAnswers WHERE
IsCorrectAnswer IS NULL AND
ExamID =
(SELECT TOP(1) ID FROM Exams E WHERE E.StudentID = S.ID ORDER BY ID DESC) --Line X
) UnansweredQuestionCount
FROM Students S
You can do it like this
SELECT S.*,
CA.*
FROM Students S
CROSS APPLY (SELECT SUM(CASE WHEN IsCorrectAnswer = 1 THEN 1 ELSE 0 END) AS CorrectAnswerCount,
SUM(CASE WHEN IsCorrectAnswer = 0 THEN 1 ELSE 0 END) AS WrongAnswerCount,
SUM(CASE WHEN IsCorrectAnswer IS NULL THEN 1 ELSE 0 END) AS UnansweredQuestionCount
FROM ExamAnswers EA
WHERE EA.ExamID = (SELECT TOP(1) ID
FROM Exams E
WHERE E.StudentID = S.ID
ORDER BY ID DESC)) CA
What about this approach :
WITH
T AS
(
SELECT Student_id,
SUM(CASE IsCorrectAnswer WHEN 1 THEN 1 END) AS COUNT_TRUE,
SUM(CASE IsCorrectAnswer WHEN 0 THEN 1 END) AS COUNT_FALSE,
SUM(CASE WHEN IsCorrectAnswer IS NULL THEN 1 END) AS COUNT_UNKNOWN
FROM ExamAnswers AS EA
WHERE EA.ExamID = (SELECT MAX(ID)
FROM Exams E
WHERE E.StudentID = S.ID)
GROUP BY Student_id
)
SELECT S.*, COUNT_TRUE, COUNT_FALSE, COUNT_UNKNOWN
FROM Students AS S
JOIN T ON S.ID = T.Student_id

How to write this SQL Server query: Add values in unique rows?

I have a query like below. The relation between table are:
Each truck may have multiple drivers. Table List connects the each row in table Truck with rows in table Driver. Now I want to get the count of unique Trucks under certain condition, and the total size of the unique Trucks under that condition.
Here is what I have:
SELECT t.Year AS [Year]
, t.Month AS [Month]
, t.Day AS [Day]
-- Count will not count NULL
, COUNT( DISTINCT (CASE WHEN (t.Sent = 1 AND r.Internal=1) THEN L.TruckId
ELSE NULL
END) ) AS [Count]
, SUM(CASE WHEN (t.Sent = 1 AND r.Internal = 1) THEN t.Size
END) AS [Size]
FROM Truck t
INNER JOIN List L ON t.Id = L.TruckId
INNER JOIN Driver r ON L.DriverId = r.Id
GROUP BY t.Year, t.Month, t.Day
the COUNT is correct, but the SUM is not.
My question is how to get this SUM? And I do not want to write 2 queries and join them.
Thanks
You can try query like below:
; with cte as (
SELECT
DISTINCT
t.Year AS [Year]
, t.Month AS [Month]
, t.Day AS [Day]
, L.TruckId,
, t.Size
FROM Truck t
INNER JOIN List L ON t.Id = L.TruckId
INNER JOIN Driver r ON L.DriverId = r.Id
WHERE t.Sent = 1 AND r.Internal=1
)
select
Year
, Month
, Day
, count(TruckId) AS [Count]
, sum(Size) AS [Size]
from cte
group by Year, Month, Day

calculation of balance after each transaction and opening bal

I have two SQL Database table namely
Cust_Table(CustID, CustName, custAddrs, CustMob, CustOpBal)
And
Trans_Table(TransId, CustID, TransAmt, TransType(bool dr/cr), Msg, TansDate)
Now I need the SQL Query for getting Statement like (Bank Passbook) for a particular
Customer ID?
Date Message Dt_Amount Cr_Amount Balance
Iam using the following query
SELECT t1.Trans_Date, t1.Trans_Msg,
(CASE WHEN t1.Trans_Type=1 THEN 'Cr' ELSE 'Dr' END) as Trans_Type,
t1.Trans_Amount,
SUM(t2.Trans_Amount*case when t2.trans_type = '1' then 1 else -1 end) as Balance
FROM [LNLCredit].[dbo].[Trans_Table] t1
INNER JOIN [LNLCredit].[dbo].[Trans_Table] t2
ON t1.cust_id = t2.cust_id AND t1.trans_id >= t2.Trans_ID
WHERE t1.Cust_ID=2
GROUP BY t1.cust_id,t1.trans_id,t1.trans_type,t1.Trans_Amount,t1.Trans_Date,t1.Trans_Msg;
Its working fine.
But I also want to add Opening Balance (from Cust_Table) to the above solution.
Please Help??????
Try this..
SELECT t1.Trans_Date, t1.Trans_Msg,
(CASE WHEN t1.Trans_Type=1 THEN 'Cr' ELSE 'Dr' END) as Trans_Type,
t1.Trans_Amount,
SUM(t2.Trans_Amount*case when t2.trans_type = '1' then 1 else -1 end) as Balance,
c.CustOpBal
FROM [LNLCredit].[dbo].[Trans_Table] t1
INNER JOIN [LNLCredit].[dbo].[Trans_Table] t2
ON t1.cust_id = t2.cust_id AND t1.trans_id >= t2.Trans_ID
INNER JOIN Cust_Table C on C.cust_id = t1.cust_id
WHERE t1.Cust_ID=2
GROUP BY t1.cust_id,t1.trans_id,t1.trans_type,t1.Trans_Amount,
t1.Trans_Date,t1.Trans_Msg,C.CustOpBal;
You need to add an extra INNER JOIN and add openingBalance column to GROUP BY and SELECT

Add a WHERE clause in a complex SQL query

I want to pass a ShowRoomId value to the query below. The Employees table has a ShowRoomId column.
How can I do it?
My SQL query is as following:
SELECT *
FROM Employees A
OUTER APPLY (SELECT TOP 1 *
FROM EmployeeBasics B
WHERE (A.EmployeeID = B.EmployeeID)
ORDER BY B.BasicUpdateDate DESC) AS B
OUTER APPLY (
SELECT C.EmployeeId , count(*) AS TotalAbsent
FROM EmployeeAbsents C
WHERE C.AbsentDate BETWEEN '2016-05-01' AND '2016-05-30' AND A.EmployeeID = C.EmployeeID
GROUP BY C.EmployeeId
) AS C
OUTER APPLY (
SELECT EmployeeId,
SUM(CASE WHEN TransctionTypeId = 1 THEN Amount ELSE 0 END) AS Payment,
SUM(CASE WHEN TransctionTypeId = 2 THEN Amount ELSE 0 END) AS RecoverSalary,
SUM(CASE WHEN TransctionTypeId = 3 THEN Amount ELSE 0 END) AS RecoverCash
FROM dbo.EmployeeAdvances D
WHERE A.EmployeeID = D.EmployeeID
GROUP BY EmployeeId
) AS D
Simply use a WHERE clause at the end as following:
... YOUR SELECT ...
WHERE Col = ...YourCondition...
OR
Use WITH keyword to keep your current SELECT-statement in a cte. Then do your query on it.
WITH cte AS
(
... YOUR SELECT ...
)
SELECT *
FROM cte
WHERE Col = ...YourCondition...
OR
You can add your SELECT-statement in to parentheses and name it with an allias name. So you can do query on it too.
SELECT *
FROM
(
... YOUR SELECT ...
) t
WHERE t.Col = ...YourCondition...
As per Giorgi Nakeuri's advice, I added the WHERE clause at the end of the statement.
And it works for me. Revised code is here:
SELECT *
FROM Employees A
OUTER APPLY (SELECT TOP 1 *
FROM EmployeeBasics B
WHERE (A.EmployeeID = B.EmployeeID)
ORDER BY B.BasicUpdateDate DESC) AS B
OUTER APPLY (
SELECT C.EmployeeId , count(*) AS TotalAbsent
FROM EmployeeAbsents C
WHERE C.AbsentDate BETWEEN '2016-05-01' AND '2016-05-30' AND A.EmployeeID = C.EmployeeID
GROUP BY C.EmployeeId
) AS C
OUTER APPLY (
SELECT EmployeeId,
SUM(CASE WHEN TransctionTypeId = 1 THEN Amount ELSE 0 END) AS Payment,
SUM(CASE WHEN TransctionTypeId = 2 THEN Amount ELSE 0 END) AS RecoverSalary,
SUM(CASE WHEN TransctionTypeId = 3 THEN Amount ELSE 0 END) AS RecoverCash
FROM dbo.EmployeeAdvances D
WHERE A.EmployeeID = D.EmployeeID
GROUP BY EmployeeId
) AS D
WHERE A.ShowRoomId = 2

Inefficient SQL query with joined tables

I have a table with 1700 rows of data. I'm querying it using the query below which pulls complimentary data from related tables too. It's currently running very slowly (around 10 seconds).
How can I improve the efficiency of this query?
SELECT [jobID] ,
(SELECT orgname
FROM pm_clients c
WHERE c.orgID IN
(SELECT orgid
FROM pm_jobs j
WHERE j.jobid=t.jobid
AND j.jobStatus>=13)) AS orgname ,
(SELECT sector
FROM pm_clients c
WHERE c.orgID IN
(SELECT orgid
FROM pm_jobs j
WHERE j.jobid=t.jobid
AND j.jobStatus>=13)) AS sector ,
(SELECT region= CASE country
WHEN 1 THEN region
ELSE
(SELECT countryname
FROM AT_A_CountryCodes x
WHERE x.id= l.country)
END
FROM PM_ClientDetails l
WHERE l.userid =
(SELECT userid
FROM pm_jobs j
WHERE j.jobid=t.jobid)) AS region ,
(SELECT postcode
FROM PM_ClientDetails l
WHERE l.userid =
(SELECT userid
FROM pm_jobs j
WHERE j.jobid=t.jobid)) AS postcode ,
(SELECT firstname
FROM users u
WHERE u.userid =
(SELECT pmid
FROM pm_jobs j
WHERE j.jobid=t.jobid)) AS PM ,
[creationDate] ,
(SELECT statusName
FROM pm_jobstatus j
WHERE j.[statusID]=t.jobStatus) AS JobStatus ,
[completionDate] ,
[deadline],
[jobTitle] ,
(SELECT currencysymbol
FROM at_a_currency c
WHERE c.currencyID =
(SELECT top(1) quoteCurrency
FROM PM_Quotes q
WHERE q.taskid IN
(SELECT taskid
FROM pm_tasks x
WHERE x.jobID=t.jobid))) AS currency ,
(SELECT sum(quoteSubTotal)
FROM PM_Quotes q
WHERE q.taskid IN
(SELECT taskid
FROM pm_tasks x
WHERE x.jobID=t.jobid)) AS subtotal ,
(SELECT sum(quoteVAT)
FROM PM_Quotes q
WHERE q.taskid IN
(SELECT taskid
FROM pm_tasks x
WHERE x.jobID=t.jobid)) AS VAT ,
(SELECT sum(quoteTotal)
FROM PM_Quotes q
WHERE q.taskid IN
(SELECT taskid
FROM pm_tasks x
WHERE x.jobID=t.jobid)) AS total ,
(SELECT [purchaseOrder]
FROM pm_jobs j
WHERE j.jobid=t.jobid) AS purchaseOrder ,
(SELECT [clientReference]
FROM pm_jobs j
WHERE j.jobid=t.jobid) AS clientReference ,
(SELECT CASE
WHEN [deadline]='1900-01-01 00:00:00' THEN 1
WHEN [completiondate]>dateadd(dd,1,[deadline]) THEN 0
WHEN [completiondate]<=dateadd(dd,1,[deadline])THEN 1
WHEN [completiondate] IS NULL THEN 0
END) AS completedOnTime
FROM [PM_jobs] t
WHERE jobStatus>=13
Edit
Thanks to #GuidoG for the response. Here's the amended query which is much faster now.
SELECT j.jobid,
c.orgname,
c.sector,
(SELECT region= CASE country
WHEN 1 THEN region
ELSE (SELECT countryname
FROM at_a_countrycodes x
WHERE x.id = l.country)
END) AS region,
l.postcode,
(SELECT firstname
FROM users u
WHERE u.userid = J.pmid) AS PM,
j.creationdate,
(SELECT statusname
FROM pm_jobstatus x
WHERE x.[statusid] = j.jobstatus) AS JobStatus,
j.[completiondate],
j.[deadline],
j.[jobtitle],
j.purchaseorder,
j.clientreference,
(SELECT currencysymbol
FROM at_a_currency c
WHERE c.currencyid = l.clientcurrency) AS currency,
Sum(q.quotesubtotal) AS subtotal,
Sum(q.quotevat) AS VAT,
Sum(q.quotetotal) AS total,
(SELECT CASE
WHEN j.[deadline] = '1900-01-01 00:00:00' THEN 1
WHEN j.[completiondate] > Dateadd(dd, 1, j.[deadline]) THEN 0
WHEN j.[completiondate] <= Dateadd(dd, 1, j.[deadline])THEN 1
WHEN j.[completiondate] IS NULL THEN 0
END) AS completedOnTime,
Count(t.taskid) AS taskcount
FROM [pm_jobs] j
INNER JOIN pm_clients c
ON j.orgid = c.orgid
INNER JOIN pm_clientdetails l
ON j.userid = l.userid
INNER JOIN pm_tasks t
ON j.jobid = t.jobid
INNER JOIN pm_quotes q
ON q.taskid = t.taskid
AND t.jobid = j.jobid
WHERE jobstatus >= 13
GROUP BY j.jobid,
c.orgname,
c.sector,
l.country,
l.region,
l.postcode,
l.firstname,
j.creationdate,
j.jobstatus,
j.completiondate,
j.deadline,
j.jobtitle,
j.purchaseorder,
j.clientreference,
l.clientcurrency,
J.pmid
ORDER BY completiondate DESC
You should consider joining instead of subquerying. Here is a small example to get you on your way:
SELECT t.jobID ,
c.orgName,
c.sector
FROM [SQL2012_921487_atlas].[dbo].[PM_jobs] t
inner join pm_clients c on t.orgID = c.orgID
WHERE jobStatus>=13
When subquerying like you did, you force SQL Server to read table pm_clients several times; joining enables it to read pm_clients only 1 time.

Resources