Distinct Record Issue in MS SQL Server 2008 query - sql

I have this query to fetch the total OrderStatus that have values 1 and 5. How do I Sum only distinct OD.OrderStatus=2 as there can be multiple records in Orderdetails table with OrderStatus as 2.
Please help
SELECT O.OrderDate,
Sum(Case When OD.OrderStatus = 2 Then 1 Else 0 End) AS OrdersOffered,
Sum(Case When OD.OrderStatus = 1 Then 1 Else 0 End) AS OrdersAccepted
FROM Orders O,OrderDetails OD
Where O.Order_ID=OD.Order_ID
GROUP BY OrderDate

So, you want it to be 1, regardless of how many you have? Maybe use SIGN?
SELECT O.OrderDate
,SIGN(Sum(Case When OD.OrderStatus = 2 Then 1 Else 0 End)) AS OrdersOffered
,Sum(Case When OD.OrderStatus = 1 Then 1 Else 0 End) AS OrdersAccepted
FROM Orders O
JOIN OrderDetails OD ON O.Order_ID=OD.Order_ID
GROUP BY OrderDate

Just use a subquery to help with your result.
SELECT
O.OrderDate,
Sum(Case When OD.OrderStatus = 2 Then 1 Else 0 End) AS OrdersOffered,
Sum(Case When OD.OrderStatus = 1 Then 1 Else 0 End) AS OrdersAccepted
FROM Orders O inner join
(Select distinct Order_ID,OrderStatus
from OrderDetails) OD on O.Order_ID=OD.Order_ID
GROUP BY OrderDate
Should do the trick...

Related

How to use a conditional aggregate for total gross

I have this query:
SELECT CAST(co.DateCreated AS DATE) AS Date,
SUM(w.Gross),
SUM(CASE WHEN co.BookingSourceId = 1 THEN 1 ELSE 0 END) as Website,
SUM(CASE WHEN co.BookingSourceId = 2 THEN 1 ELSE 0 END) as Phone,
COUNT(*) as Total_Orders
FROM [Sterlingbuild].[dbo].[CustomerOrder] co
INNER JOIN ( SELECT Gross, CustomerOrderId, p.ProductBrandId
FROM [Sterlingbuild].[dbo].[CustomerOrderItem] coi
INNER JOIN [Sterlingbuild].[dbo].[Product] p ON coi.ProductId = p.ProductId
) w ON co.CustomerOrderId = w.CustomerOrderId
WHERE CustomerOrderStatusId = 7 AND DepartmentId = 1 AND w.ProductBrandId = 7
GROUP BY CAST(co.DateCreated AS DATE)
ORDER BY CAST(co.DateCreated AS DATE)
At the moment it returns the number of orders made by phone/website however I want the total GROSS for both phone/website how do I amend the query to achieve this.
Using SQL server
Sum the gross:
SUM(CASE WHEN co.BookingSourceId = 1 THEN w.gross ELSE 0 END) as Website_gross,
SUM(CASE WHEN co.BookingSourceId = 2 THEN w.gross ELSE 0 END) as Phone_gross,

Union with Group By

Had a look at other questions, tried different things but still returning more than one row.
Problem with Union on 2 tables, with group by clause. There should only be one row returned, grouped by the serviceID.
SELECT
serviceID,
serviceName,
FullCount,
WaitingCount,
InProgressCount
from (
select
a.serviceID,
serviceName,
count(applicantID) FullCount,
ISNULL(SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END),0) AS WaitingCount,
ISNULL(SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END),0) AS InProgressCount
from Products s
left join Assigns a on a.serviceID = s.productID
WHERE s.clientID = #ClientID
group by serviceID, serviceName
UNION
select
s.serviceID,
p.serviceName,
count(s.ApplicantID) FullCount,
ISNULL(SUM(CASE WHEN s.status = 0 THEN 1 ELSE 0 END),0) AS WaitingCount,
ISNULL(SUM(CASE WHEN s.status = 1 THEN 1 ELSE 0 END),0) AS InProgressCount
from Legacies s
Left Join Products p on s.serviceID = p.productID
WHERE s.client = #CompanyName
group by serviceID, serviceName
) t
GROUP BY serviceID, serviceName
I'm always getting 2 rows returned, one from each of the tables. I need to group them both together so it only returns 1 row, based on the servicedID.
The data I'm trying to return is from the following tables..
Products Table
productID serviceName
-------------------------
1 Gold Service
2 Silver Service
3 Bronze Service
Assigns Table
ApplicantID serviceID status
-------------------------------------
1 1 0
2 1 0
3 1 1
4 2 0
5 1 1
Legacies Table
ApplicantID serviceID status
-------------------------------------
1 1 0
2 1 0
3 1 0
4 2 0
5 1 1
The result I'm trying to get is one row per serviceID, to show how many applicants are on this service in both the Legacies and Assigns table, something like:-
serviceID serviceName FullCount WaitingCount InProgressCount
----------------------------------------------------------------
1 Gold Service 8 5 3
2 Silver Service 2 2 0
3 Bronze Service 0 0 0
FullCount is a total number of applicants on each service, WaitingCount is the number of applicants on the service with a status of '0' and InProgressCount is the number on this service with a status of '1'
Based on additional information, I think you can just union all the Legacies and Assigns tables.
still untested
select serviceID, servicename, count(*) fullcount
,sum(case when status = 0 THEN 1 ELSE 0 END) AS WaitingCount
,SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS InProgressCount
from (
select ApplicantID, serviceID, status
from Assigns
WHERE clientID = #ClientID
union all
select ApplicantID, serviceID, status
from Legacies
WHERE clientID = #ClientID
) combined
left join Products P on P.productID = combined.serviceID
group by serviceID, servicename
below is before edit
It's hard to tell because you do not post enough information (no sample data, no table structures, no expected output). But I think you can probably combine it all into 1 query:
untested which should be obvious with the lack of information.
SELECT isnull(a.serviceID, L.serviceID) serviceID, p.serviceName
,count(*) FullCount, SUM(CASE WHEN isnull(a.status, L.status) = 0 THEN 1 ELSE 0 END) WaitingCount
,sum(CASE WHEN isnull(a.status, L.status) = 1 THEN 1 ELSE 0 END) InProgressCount
from Legacies L
full outer join Assigns a on a.serviceID = L.serviceID
right outer join Products P on P.productID = isnull(a.serviceID, L.serviceID)
where (P.clientID = #ClientID
or L.client = #CompanyName
)
group by isnull(a.serviceID, L.serviceID), p.serviceName

How to calculate a Cumulative total using SQL

I have a Tickets table in My database , each Ticket have a status_id (1,2,3)
1: Ticket IN PROGRESS
2: Ticket Out Of time
3: Ticket Closed
I want using SQL to calculate the number of tickets for each status .
Calculate the cumulative total for each Status in a specific Date, I have already a column affectation_Date that contains the date where the status of ticket has been changed .
Use conditional aggregation as
SELECT TicketID,
AffectationDate,
SUM(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END) InProgress,
SUM(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END) OuOfTime,
SUM(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END) Closed,
COUNT(1) Total
FROM Tickets
GROUP BY TicketID,
AffectationDate
ORDER BY TicketID,
AffectationDate;
Or if you want to GROUP BY AffectationDate only
SELECT AffectationDate,
SUM(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END) TotalInProgress,
SUM(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END) TotalOutOfTime,
SUM(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END) TotalClosed,
COUNT(1) TotalStatusThisDate
FROM Tickets
GROUP BY AffectationDate
ORDER BY AffectationDate;
Live Demo
Using conditional counts.
SELECT affectation_Date,
COUNT(CASE WHEN status_id = 1 THEN 1 END) AS TotalInProgress,
COUNT(CASE WHEN status_id = 2 THEN 1 END) AS TotalOutOfTime,
COUNT(CASE WHEN status_id = 3 THEN 1 END) AS TotalClosed
FROM Tickets t
GROUP BY affectation_Date
ORDER BY affectation_Date
you may use the desired filter condition for the date criteria
SELECT COUNT(1), STATUS
FROM tickets
WHERE affectation_Date >= 'someDate'
group by status
Regards
You just need to group by status and count the number of tickets in each group:
select status, count(*) as number
from Tickets
where dt >= '2019-01-01 00:00:00' and dt < '2019-01-02 00:00:00'
group by status
having status >= 1 and status <= 3
This adds the Cumulative Sum to the existing answers:
SELECT AffectationDate,
Sum(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END) AS TotalInProgress,
Sum(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END) AS TotalOutOfTime,
Sum(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END) AS TotalClosed,
Count(*) as TotalStatusThisDate,
Sum(Sum(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END)) Over (ORDER BY AffectationDate) AS cumTotalInProgress,
Sum(Sum(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END)) Over (ORDER BY AffectationDate) AS cumTotalOutOfTime,
Sum(Sum(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END)) Over (ORDER BY AffectationDate) AS cumTotalClosed,
Sum(Count(*)) Over (ORDER BY AffectationDate) AS cumTotalStatusThisDate
FROM Tickets
GROUP BY AffectationDate
ORDER BY AffectationDate;

sql subquery that collects from 3 rows

I have a huge database with over 4 million rows that look like that:
Customer ID Shop
1 Asda
1 Sainsbury
1 Tesco
2 TEsco
2 Tesco
I need to count customers that within last 4 weeks had shopped in all 3 shops Tesco Sainsbury and Asda. Can you please advice if its possible to do it with subqueries?
This is an example of a "set-within-sets" subquery. You can solve it with aggregation:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
This structure is quite flexible. So if you wanted Asda and Tesco but not Sainsbury, then you would do:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) = 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
EDIT:
If you want a count, then use this as a subquery and count the results:
select count(*)
from (select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0
) t

Fetch the total from the result of a query

The query i am using is
select convert(varchar(10), sales.saledate, 103) [SaleDate], SUM(sales.Domestic) [Domestic], SUM(sales.Export) [Export], SUM(sales.Import) [Import],
SUM(sales.Value) [Value], Sum(sales.Cancelled) [Cancelled], sum(sales.cancelledValue) [CancelledValue], SUM(sales.totalValue) [TotalValue]
from
(
select max(j.SaleDate) SaleDate,
case when max(oc.Code) = 'AU' and max(dc.Code) = 'AU' then 1 else 0 end [Domestic],
case when max(oc.Code) = 'AU' and max(dc.Code) <> 'AU' then 1 else 0 end [Export],
case when max(oc.Code) <> 'AU' and max(dc.Code) = 'AU' then 1 else 0 end [Import],
1 [Total],
max(ic.Total) [Value],
case when max(c.CancelDate) is not null then 1 else 0 end [Cancelled],
case when max(c.CancelDate) is not null then max(ic.Total) else 0 end [CancelledValue],
case when max(c.CancelDate) is null then max(ic.Total) else 0 end [TotalValue]
from invoices i
left join Jobs j on i.JobKey = j.JobKey
inner join tasks t on j.jobkey = t.jobkey
inner join Consignments c on t.TaskKey = c.consignmentkey
inner join places op on c.originplacekey = op.placekey
inner join places dp on c.destinationplacekey = dp.placekey
inner join places oC on dbo.ParentPlaceKey(c.originPlaceKey) = oc.placekey
inner join places dC on dbo.ParentPlaceKey(c.destinationplacekey) = dc.placekey
left join (select consignmentKey, sum(Value) [Value] from ConsignmentItems ci group by consignmentkey ) ci on ci.ConsignmentKey = c.ConsignmentKey
left join (select invoicekey, sum(case when ci.ChargeItemKey = 'FRT_SLL' then oc.Value else 0 end) [Freight],
sum(case when ci.ChargeItemKey = 'WTY_SLL' then oc.Value else 0 end) [Warranty],
sum(case when ci.ChargeType = 4 then oc.Value else 0 end) [Total] from InvoiceCharges ic
left join OptionCharges oc on ic.OptionChargeKey = oc.OptionChargeKey
left join ChargeItems ci on oc.ChargeItemKey = ci.ChargeItemKey
group by invoicekey
) ic on ic.InvoiceKey = i.InvoiceKey
where
j.SaleDate >= '01-Apr-2013' and j.SaleDate <= '10-May-2013'
and
j.operationalstorekey = dbo.StoreCode('AU-WEB')
and j.saledate is not null and SelectedOptionKey is not null
group by j.jobkey
) sales
group by convert(varchar(10), sales.saledate, 103)
order by max(sales.saledate)
The result of a sql query is
SaleDate Domestic Export Import Value Cancelled CancelledValue Totalvalue
11/04/2013 1 0 0 47.200 0 0.0000 47.2000
16/04/2013 6 0 0 249.750 0 0.0000 249.7500
22/04/2013 0 1 0 223.480 0 0.0000 223.4800
23/04/2013 0 3 0 670.440 0 0.0000 670.4400
I want result like (want to add the TOTALS at the end)
SaleDate Domestic Export Import Value Cancelled CancelledValue Totalvalue
11/04/2013 1 0 0 47.200 0 0.0000 47.2000
16/04/2013 6 0 0 249.750 0 0.0000 249.7500
22/04/2013 0 1 0 223.480 0 0.0000 223.4800
23/04/2013 0 3 0 670.440 0 0.0000 670.4400
TOTALS 7 4 0 1190.432 0 0 1190.432
Can anyone please tell me how to achieve this in above query, i am trying with temp tables which i dont want.
Thanks.
You can achieve this by adding an UNION at the end of your result. Something like:
... order by max(sales.saledate)
UNION
(SELECT "TOTALS", SUM(sales.Domestic) AS Domestic, SUM(sales.Export) AS Export,
SUM(sales.Import) AS Import, SUM(sales.Value) [Value], Sum(sales.Cancelled) AS Cancelled, sum(sales.cancelledValue) AS CancelledValue, SUM(sales.totalValue) AS TotalValue
FROM "your_big_query"...
WHERE ...
)
And this time remove the group by convert(varchar(10), sales.saledate, 103)
EDIT
Or you can use the GROUP BY Modifiers try to use this in the GROUP BY statement:
group by convert(varchar(10), sales.saledate, 103) WITH ROLLUP
You can read the official documentation here with some examples too.
Hope this works!!