**Query 1:**
SELECT ID
, COUNT(DISTINCT A.order_id) AS order_count
FROM table_1 B
JOIN table_2 A
ON A.order_id = B.order_id
WHERE
AND A.order_status IN ('PROCESSING', 'COMPLETED')
and B.fullfilled_cd = 'DELIVERY'
GROUP BY ID;
**Query 2:**
SELECT ID
, COUNT(DISTINCT A.order_id) AS order_count
FROM table_1 B
JOIN table_2 A
ON A.order_id = B.order_id
WHERE
AND A.order_status IN ('PROCESSING', 'COMPLETED')
and B.fullfilled_cd = 'PURCHASE'
GROUP BY ID;
Kindly guide me how to combine these 2 queries into a single query. COUNT_IF is not possible as fullfilled_cd is not a BOOLEAN column. Can we use CASE statement?
Using conditional aggregation:
SELECT ID
,COUNT(DISTINCT CASE WHEN B.fullfilled_cd = 'DELIVERY' THEN A.order_id END) AS order_count_delivery
,COUNT(DISTINCT CASE WHEN B.fullfilled_cd = 'PURCHASE' THEN A.order_id END) AS order_count_purchase
FROM table_1 B
JOIN table_2 A
ON A.order_id = B.order_id
WHERE A.order_status IN ('PROCESSING', 'COMPLETED')
AND B.fullfilled_cd IN ('DELIVERY','PURCHASE')
GROUP BY ID;
Related
I have an sql query where I count receipts. I want to count a) all receipts, b) receipts where the related customer has registered in the same year/month, c) receipts where the related customer has visited the store at least 4 times. The query is grouped over year and month. I hope it is comprehensible.
SELECT t.Year, t.Month,
COUNT(DISTINCT fs.Receipt) AS NumberOfGuests, //fs.Receipt is Receipt Number
COUNT(DISTINCT
(CASE
WHEN YEAR(c.RegistrationDate) = t.Year AND MONTH(c.RegistrationDate) = t.Month
THEN fs.Receipt END)) AS NumberOfNewGuests,
COUNT(DISTINCT
(CASE WHEN
(
SELECT COUNT(DISTINCT fs_sub.Receipt)
FROM Dimension_Time AS t_sub
LEFT OUTER JOIN Fact_Sales AS fs_sub ON t_sub.ID = fs_sub.Time AND fs_sub.Store = #storeID
WHERE t_sub.Time = t.Time AND fs_sub.CustomerID = fs.CustomerID
) > 3
THEN fs.Receipt END)) AS NumberOfRegularGuests
FROM Dimension_Time AS t
LEFT OUTER JOIN Fact_Sales AS fs ON t.ID = fs.Time AND fs.Store = #storeID
LEFT OUTER JOIN Dimension_Customer AS c ON fs.Customer = c.ID
WHERE (t.Time >= DATEFROMPARTS(2021 - 1, 5, 1)) AND (t.Time <= EOMONTH(DATEFROMPARTS(2021, 5, 1)))
GROUP BY t.Month, t.Year
ORDER BY t.Year, t.Month
NumberOfGuests and NumberOfNewGuests works fine, but with NumberOfRegularGuests, I get an error:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Is it possible to build the query another way to avoid the error?
You can put the subquery into an APPLY:
SELECT t.Year, t.Month,
COUNT(DISTINCT fs.Receipt) AS NumberOfGuests, //fs.Receipt is Receipt Number
COUNT(DISTINCT
(CASE
WHEN YEAR(c.RegistrationDate) = t.Year AND MONTH(c.RegistrationDate) = t.Month
THEN fs.Receipt END)) AS NumberOfNewGuests,
COUNT(DISTINCT
(CASE WHEN t2.countReceipts > 3 THEN fs.Receipt END)
) AS NumberOfRegularGuests
FROM Dimension_Time AS t
LEFT OUTER JOIN Fact_Sales AS fs ON t.ID = fs.Time AND fs.Store = #storeID
LEFT OUTER JOIN Dimension_Customer AS c ON fs.Customer = c.ID
OUTER APPLY (
SELECT COUNT(DISTINCT fs_sub.Receipt) AS countReceipts
FROM Dimension_Time AS t_sub
LEFT OUTER JOIN Fact_Sales AS fs_sub ON t_sub.ID = fs_sub.Time AND fs_sub.Store = #storeID
WHERE t_sub.Time = t.Time AND fs_sub.CustomerID = fs.CustomerID
) t2
WHERE (t.Time >= DATEFROMPARTS(2021 - 1, 5, 1)) AND (t.Time <= EOMONTH(DATEFROMPARTS(2021, 5, 1)))
GROUP BY t.Month, t.Year
ORDER BY t.Year, t.Month;
But a subquery of this type is usually pretty inefficient (although this can depend on indexing as well as cardinalities ie how much of Fact_Sales is actually being used after filtering on dates). It can be replace by a windowed aggregate.
SELECT t.Year, t.Month,
COUNT(DISTINCT fs.Receipt) AS NumberOfGuests, //fs.Receipt is Receipt Number
COUNT(DISTINCT
(CASE
WHEN YEAR(c.RegistrationDate) = t.Year AND MONTH(c.RegistrationDate) = t.Month
THEN fs.Receipt END)) AS NumberOfNewGuests,
COUNT(DISTINCT
(CASE WHEN fs.countReceipts > 3 THEN fs.Receipt END)
) AS NumberOfRegularGuests
FROM Dimension_Time AS t
LEFT OUTER JOIN (
SELECT *,
COUNT(*) OVER (PARTITION BY fs.CustomerID) AS countReceipts
FROM Fact_Sales
) AS fs ON t.ID = fs.Time AND fs.Store = #storeID
LEFT OUTER JOIN Dimension_Customer AS c ON fs.Customer = c.ID
WHERE (t.Time >= DATEFROMPARTS(2021 - 1, 5, 1)) AND (t.Time <= EOMONTH(DATEFROMPARTS(2021, 5, 1)))
GROUP BY t.Month, t.Year
ORDER BY t.Year, t.Month;
It's unclear why you have COUNT(DISTINCT as opposed to just COUNT, this is usually an indication of a poorly thought-out join.
If it is indeed the case that there are multiple Fact_Sales with the same Receipt then you would need to change the window aggregate, as you cannot use COUNT(DISTINCT...) OVER...
SELECT t.Year, t.Month,
COUNT(DISTINCT fs.Receipt) AS NumberOfGuests, //fs.Receipt is Receipt Number
COUNT(DISTINCT
(CASE
WHEN YEAR(c.RegistrationDate) = t.Year AND MONTH(c.RegistrationDate) = t.Month
THEN fs.Receipt END)) AS NumberOfNewGuests,
COUNT(DISTINCT
(CASE WHEN fs.countReceipts > 3 THEN fs.Receipt END)
) AS NumberOfRegularGuests
FROM Dimension_Time AS t
LEFT OUTER JOIN (
SELECT *,
MAX(rn) OVER (PARTITION BY fs.CustomerID) AS countReceipts
FROM (
SELECT *,
DENSE_RANK() OVER (PARTITION BY fs.CustomerID ORDER BY fs.Receipt) AS rn
FROM Fact_Sales
) AS fs
) AS fs ON t.ID = fs.Time AND fs.Store = #storeID
LEFT OUTER JOIN Dimension_Customer AS c ON fs.Customer = c.ID
WHERE (t.Time >= DATEFROMPARTS(2021 - 1, 5, 1)) AND (t.Time <= EOMONTH(DATEFROMPARTS(2021, 5, 1)))
GROUP BY t.Month, t.Year
ORDER BY t.Year, t.Month;
I am trying to insert into table using select from another table with multiple case scenarios. Each person has more than one value, which gives multiple rows in the jointable. I want to select col2 based on col1 from the jointable.
The outcome so far, is 3 line of same person, 1 of the 3 values in each row.
See result here
INSERT INTO #temp (Name, WageNo, Tiltraedelses_dato, Jubilaeum ,Sabbatical, Anciennitet)
SELECT
e.FirstName,
e.WageSystemKey,
e.[StartDate],
CASE WHEN v.EmployeeCustomColumnId = 2 THEN v.Value END,
CASE WHEN v.EmployeeCustomColumnId = 3 THEN v.Value END,
CASE WHEN v.EmployeeCustomColumnId = 1 THEN v.Value END
FROM Employees e
LEFT JOIN EmployeeCustomValue v on e.EmployeeId = v.EmployeeId
SELECT * FROM #temp
I think you need a group by with conditional aggregation, something like this
INSERT INTO #temp (Name, WageNo, Tiltraedelses_dato, Jubilaeum ,Sabbatical, Anciennitet)
SELECT
e.FirstName,
e.WageSystemKey,
e.[StartDate],
max(CASE WHEN v.EmployeeCustomColumnId = 2 THEN v.Value END),
max(CASE WHEN v.EmployeeCustomColumnId = 3 THEN v.Value END),
max(CASE WHEN v.EmployeeCustomColumnId = 1 THEN v.Value END)
FROM Employees e
LEFT JOIN EmployeeCustomValue v on e.EmployeeId = v.EmployeeId
group by e.FirstName,
e.WageSystemKey,
e.[StartDate]
Here are a couple of other ways to go about this.
INSERT INTO #temp (Name, WageNo, Tiltraedelses_dato, Jubilaeum ,Sabbatical, Anciennitet)
SELECT
e.FirstName,
e.WageSystemKey,
e.[StartDate],
v2.Value,
v3.Value,
v1.Value
FROM Employees e
LEFT JOIN EmployeeCustomValue v1 on e.EmployeeId = v1.EmployeeId and v1.EmployeeCustomColumnId = 1
LEFT JOIN EmployeeCustomValue v2 on e.EmployeeId = v2.EmployeeId and v2.EmployeeCustomColumnId = 2
LEFT JOIN EmployeeCustomValue v3 on e.EmployeeId = v3.EmployeeId and v3.EmployeeCustomColumnId = 3
Or
INSERT INTO #temp (Name, WageNo, Tiltraedelses_dato, Jubilaeum ,Sabbatical, Anciennitet)
SELECT FirstName, WageSystemKey, [StartDate],
MAX(Jubilaeum) AS Jubilaeum, MAX(Sabbatical) AS Sabbatical,
MAX(Anciennitet) AS Anciennitet
FROM (SELECT
e.FirstName,
e.WageSystemKey,
e.[StartDate],
CASE WHEN v.EmployeeCustomColumnId = 2 THEN v.Value END AS Jubilaeum,
CASE WHEN v.EmployeeCustomColumnId = 3 THEN v.Value END AS Sabbatical,
CASE WHEN v.EmployeeCustomColumnId = 1 THEN v.Value END AS Anciennitet
FROM Employees e
LEFT JOIN EmployeeCustomValue v on e.EmployeeId = v.EmployeeId) AA
GROUP BY FirstName, WageSystemKey, [StartDate]
I have the following query. And need to sum all returned by the query "distinct case" values withing a row populated in another column "TotalDepartmentsCount"
;WITH CTE
AS
(
Select t.ID As [CTE_ID]
,count(distinct case when e.Department='M' then t.ID else null end) as M_Marketing
,count(distinct case when e.Department='S' then t.ID else null end) as S_Sales
,count(distinct case when e.Department='U' then t.ID else null end) as U_Utilization
,count(distinct case when e.Department=' ' then t.ID else null end) as No_NoDepartment
From dbo.Table t (nolock)
Left Join dbo.ClearedEmployee ce (nolock) ON t.ID = ce.building_fk
Join dbo.Employee e (nolock) ON ce.employee_fk = e.employee_pk
Group By t.ID
)
Select *, t.ID
From CTE c (nolock)
FULL JOIN dbo.Table t (nolock) ON t.ID=c.[CTE_ID]
Order By t.ID ASC;
To do it I added this code in the select list:
sum(cast(e.Department as int)) As TotalDepartmentsCount
But this does not sum up correctly (see screenshot below). Please advise.
This is how I want to have my output (see the TotalDepartmentsCount table)
Why not just add the columns together once you've calculated them? e.g.:
;WITH CTE
AS
(
Select t.ID As [CTE_ID]
,count(distinct case when e.Department='M' then t.ID else null end) as M_Marketing
,count(distinct case when e.Department='S' then t.ID else null end) as S_Sales
,count(distinct case when e.Department='U' then t.ID else null end) as U_Utilization
,count(distinct case when e.Department=' ' then t.ID else null end) as No_NoDepartment
From dbo.Table t (nolock)
Left Join dbo.ClearedEmployee ce (nolock) ON t.ID = ce.building_fk
Join dbo.Employee e (nolock) ON ce.employee_fk = e.employee_pk
Group By t.ID
)
Select *
, t.ID
, isnull(M_Marketing, 0) + isnull(S_Sales, 0) + isnull(U_Utilization, 0) + isnull(No_NoDepartment, 0) as TotalDepartments
From CTE c (nolock)
FULL JOIN dbo.Table t (nolock) ON t.ID=c.[CTE_ID]
Order By t.ID ASC;
Your CTE currently computes 4 counts by filtering based on department. What you want is a 5th count that includes all rows (e.g., no filtering). So you should be able to add that column to your CTE like so:
;WITH CTE
AS
(
Select t.ID As [CTE_ID]
,count(distinct case when e.Department='M' then t.ID else null end) as M_Marketing
,count(distinct case when e.Department='S' then t.ID else null end) as S_Sales
,count(distinct case when e.Department='U' then t.ID else null end) as U_Utilization
,count(distinct case when e.Department=' ' then t.ID else null end) as No_NoDepartment
,count(distinct t.ID) as TotalDepartmentsCount
From dbo.Table t (nolock)
Left Join dbo.ClearedEmployee ce (nolock) ON t.ID = ce.building_fk
Join dbo.Employee e (nolock) ON ce.employee_fk = e.employee_pk
Group By t.ID
)
The above will work as long as the Department column only contains the four specific values used in distinct cases ('M', 'S', 'U', and ' '). If you can have other Department values that you need to ignore, you can change the TotalDepartmentsCount column in your CTE to be calculated like this:
,count(distinct case when e.Department in ('M', 'S', 'U', ' ') then t.ID else null end) as TotalDepartmentsCount
Or you can simply compute the sum of the four columns in your final query, like so:
Select c.*
, (M_Marketing + S_Sales + U_Utilization + No_NoDepartment) as TotalDepartmentsCount
, t.ID
From CTE c (nolock)
I am trying to create one output using a view that would combine the quotes from Query 2 with the quotes from Query 1 and the policies from Query 3 with the policies from Query 1. Query 1 is my main query ... 2 and 3 would be left joined.
Query 1:
SELECT
A.AgencyId,
SUM(A.Quotes) AS Quotes,
SUM(A.NB) AS Policies,
CONVERT(DATE, A.Date) AS Date,
C.WeekEndDate
FROM
dbo.Agent_Qts_Daily A
INNER JOIN
dbo.AgentList B ON A.AgencyID = B.AgencyID
LEFT JOIN
dbo.WE_DATES C ON A.Date = C.Date
WHERE
Year = '2016'
GROUP BY
A.AgencyID, A.Date, C.WeekEndDate
Query 2:
SELECT
B.AgencyID,
SUM(A.Quote_Cnt) AS Quotes,
CONVERT(DATE, A.DateRecd) AS Date,
C.WeekEndDate
FROM
dbo.TestData A
INNER JOIN
dbo.AgentList B ON A.AgtID = B.AGTID
LEFT JOIN
dbo.WE_DATES C ON A.DateRecd = C.Date
WHERE
A.FirmGroup <> 'ABC'
AND A.Source = 'DEF'
AND C.Year = '2016'
GROUP BY
B.AgencyID, A.DateRecd, C.WeekEndDate
Query 3:
SELECT
B.AgencyID,
SUM(A.sold_Cnt) AS Policies,
CONVERT(DATE, A.DateBound) AS Date,
C.WeekEndDate
FROM
dbo.TestData A
INNER JOIN
dbo.AgentList B ON A.AgtID = B.AGTID
LEFT JOIN
dbo.WE_DATES C ON A.DateBound = C.Date
WHERE
A.FirmGroup <> 'ABC'
AND A.sold_Cnt = '1'
AND A.Source = 'DEF'
AND C.Year = '2016'
GROUP BY
B.AgencyID, A.DateBound, C.WeekEndDate
You can do something like this or you can also use an sp to meet the same criteria
CREATE VIEW ViewName
AS
SELECT
A.AgencyId,
SUM(A.Quotes) AS Quotes,
SUM(A.NB) AS Policies,
CONVERT(DATE, A.Date) AS Date,
C.WeekEndDate
FROM
dbo.Agent_Qts_Daily A
INNER JOIN dbo.AgentList B ON A.AgencyID = B.AgencyID
LEFT JOIN dbo.WE_DATES C ON A.Date = C.Date
WHERE Year = '2016'
GROUP BY
A.AgencyID,
A.Date,
C.WeekEndDate
UNION ALL
SELECT
B.AgencyID,
SUM(A.Quote_Cnt) AS Quotes,
0 AS Policies,
CONVERT(DATE, A.DateRecd) AS Date,
C.WeekEndDate
FROM
dbo.TestData A
INNER JOIN dbo.AgentList B ON A.AgtID = B.AGTID
LEFT JOIN dbo.WE_DATES C ON A.DateRecd = C.Date
WHERE
A.FirmGroup <> 'ABC'
AND A.Source = 'DEF'
AND C.Year = '2016'
GROUP BY
B.AgencyID,
A.DateRecd,
C.WeekEndDate
UNION ALL
SELECT
B.AgencyID,
0 AS Quotes,
SUM(A.sold_Cnt) AS Policies,
CONVERT(DATE, A.DateBound) AS Date,
C.WeekEndDate
FROM
dbo.TestData A
INNER JOIN dbo.AgentList B ON A.AgtID = B.AGTID
LEFT JOIN dbo.WE_DATES C ON A.DateBound = C.Date
WHERE
A.FirmGroup <> 'ABC'
AND A.sold_Cnt = '1'
AND A.Source = 'DEF'
AND C.Year = '2016'
GROUP BY
B.AgencyID,
A.DateBound,
C.WeekEndDate
Consider the data below which is stored in temp table. How to get all those ID / State / Group combination which does not have Status record having 'AC' value ?
Data Image
The result should yield
ID State Group
2 FL LI
3 FL VA
5 FL LI
There are several query patterns that will achieve that result.
An example of one of those patterns, using an GROUP BY operation, with aggregation of a condition (to exclude the groupings where there's a row in the grouping that has a status value of 'AC')
SELECT t.id
, t.state
, t.group
FROM mytable t
GROUP
BY t.id
, t.state
, t.group
HAVING MAX(CASE WHEN t.status='AC' THEN 1 ELSE 0 END) = 0
An example of another pattern, using an anti-join:
SELECT t.id
, t.state
, t.group
FROM mytable t
LEFT
JOIN mytable s
ON s.id = t.id
AND s.state = t.state
AND s.group = t.group
AND s.status = 'AC'
WHERE s.id IS NULL
GROUP
BY t.id
, t.state
, t.group
Select *
FROM TableName t
WHERE NOT EXISTS (SELECT 1
FROM TableName
WHERE [State] = t.[State]
AND [Group] = t.[Group]
AND [Status] = 'AC')