How to use count for a case statement - sql

I'm using the below code to get the count of every case statements which has sum inside the case statements but I'm getting the error message.
SELECT
count(case when SUM(Orders.Sales)>10000 then 1 end) as High,
count(case when SUM(Orders.Sales)>5000 and SUM(Orders.Sales)<9999 then
SUM(Orders.Sales) end) as Medium,
count(case when SUM(Orders.Sales)<5000 then SUM(Orders.Sales) end) as Low
FROM Orders
INNER JOIN Returns ON Orders.[Order ID] = Returns.[Order ID]
OUTPUT
This is the required output which I'm supposed to be expected.

I feel that you should be doing the outer count rollups over a subquery which aggregates by order:
SELECT
COUNT(CASE WHEN sales < 5000 THEN 1 END) AS Low,
COUNT(CASE WHEN sales < 9999 THEN 1 END) AS Medium,
COUNT(CASE WHEN sales >= 9999 THEN 1 END) AS High
FROM
(
SELECT o.[Order ID], SUM(o.Sales) AS sales
FROM Orders o
INNER JOIN Returns r ON o.[Order ID] = r.[Order ID]
GROUP BY o.[Order ID]
) t;
That being said, I don't actually know what the purpose of joining Orders to the Returns table is. If you intend to only find sales amounts from orders which have been returned, then maybe this makes sense. Otherwise, maybe it doesn't make sense.

Related

SQL - Dividing aggregated fields, very new to SQL

I have list of line items from invoices with a field that indicates if a line was delivered or picked up. I need to find a percentage of delivered items from the total number of lines.
SALES_NBR | Total | Deliveryrate
1 = Delivered 0 = picked up from FULFILLMENT.
SELECT SALES_NBR,
COUNT (ITEMS) as Total,
SUM (case when FULFILLMENT = '1' then 1 else 0 end) as delivered,
(SELECT delivered/total) as Deliveryrate
FROM Invoice_table
WHERE STORE IN '0123'
And SALE_DATE >='2020-02-01'
And SALE_DATE <='2020-02-07'
Group By SALES_NBR, Deliveryrate;
My query executes but never finishes for some reason. Is there any easier way to do this? Fulfillment field does not contain any NULL values.
Any help would be appreciated.
I need to find a percentage of delivered items from the total number of lines.
The simplest method is to use avg():
select SALES_NBR,
avg(fulfillment) as delivered_ratio
from Invoice_table
where STORE = '0123' and
SALE_DATE >='2020-02-01' and
SALE_DATE <='2020-02-07'
group by SALES_NBR;
I'm not sure if the group by sales_nbr is needed.
If you want to get a "nice" query, you can use subqueries like this:
select
qry.*,
qry.delivered/qry.total as Deliveryrate
from (
select
SALES_NBR,
count(ITEMS) as Total,
sum(case when FULFILLMENT = '1' then 1 else 0 end) as delivered
from Invoice_table
where STORE IN '0123'
and SALE_DATE >='2020-02-01'
and SALE_DATE <='2020-02-07'
group by SALES_NBR
) qry;
But I think this one, even being ugglier, could perform faster:
select
SALES_NBR,
count(ITEMS) as Total,
sum(case when FULFILLMENT = '1' then 1 else 0 end) as delivered,
sum(case when FULFILLMENT = '1' then 1 else 0 end)/count(ITEMS) as Deliveryrate
from Invoice_table
where STORE IN '0123'
and SALE_DATE >='2020-02-01'
and SALE_DATE <='2020-02-07'
group by SALES_NBR

BigQuery: group counters by month after self-join

I have table that looks like this:
I'm trying to build a query, that will show specific partnerId counters groupped by keywordName and month.
To solve first part(without grouping by month), I've built this query:
SELECT keywordName, COUNT(keywordName) as total, IFNULL(b.ebay_count, 0) as ebay, IFNULL(c.amazon_count, 0) as amazon,
FROM LogFilesv2_Dataset.FR_Clickstats_v2 a
LEFT JOIN
(SELECT keywordName as kw , SUM(CASE WHEN partnerId='eBay' THEN 1 ELSE 0 END) as ebay_count
FROM LogFilesv2_Dataset.FR_Clickstats_v2
WHERE partnerId = 'eBay' GROUP BY kw) b
ON keywordName = b.kw
LEFT JOIN
(SELECT keywordName as kw , SUM(CASE WHEN partnerId='AmazonApi' THEN 1 ELSE 0 END) as amazon_count
FROM LogFilesv2_Dataset.FR_Clickstats_v2
WHERE partnerId = 'AmazonApi' GROUP BY kw) c
ON keywordName = c.kw
WHERE keywordName = 'flipper' -- just to filter out single kw.
GROUP BY keywordName, ebay, amazon
It works quite well and returns following output:
Now I'm trying to make additional group by month, but all my attempts returned incorrect results.
Final output supposed to be similar to this:
You can do this with conditional aggregation:
select
date_trunc(dt, month) dt,
keywordName,
count(*) total,
sum(case when partnerId = 'eBay' then 1 else 0 end) ebay,
sum(case when partnerId = 'AmazonApi' then 1 else 0 end) amazon
from LogFilesv2_Dataset.FR_Clickstats_v2
group by date_trun(dt, month), keywordName

Complex SQL query with aggregate functions

I have 3 tables
Sales journal SALES:
DATE - Sale date
T_CODE - Product code
QUAN - Quantity sold
Product journal PRODUCTS:
CODE - Product code
NAME - Product name
Prices journal PRICES:
T_CODE - Product code
DATE - Date of change of price(i.e. the changed price is valid from that date onwards till the next change of price)
COST - The price of the product
I need to summarize total quantity sold and total value sold for first three months of 2018
I've tried to construct SQL query for this as follows:
SELECT PRODUCTS.NAME, PRODUCT.T_CODE
(SELECT SUM(SALES.QUAN) WHERE SALES.DATE BETWEEN '01.01.2018' AND '31.01.2018') AS JANUARY_QUANTITY
(SELECT SUM(SALES.QUAN)*PRICES.COST FROM SALES INNER JOIN PRICES ON PRICES.T_CODE = SALES.T_CODE) AS JANUARY_VALUE
(SELECT SUM(SALES.QUAN) WHERE SALES.DATE BETWEEN '01.02.2018' AND '28.02.2018') AS FEBRUARY_QUANTITY
(SELECT SUM(SALES.QUAN)*PRICES.COST FROM SALES INNER JOIN PRICES ON PRICES.T_CODE = SALES.T_CODE) AS FEBRUARY_VALUE
(SELECT SUM(SALES.QUAN) WHERE SALES.DATE BETWEEN '01.03.2018' AND '31.03.2018') AS MARCH_QUANTITY
(SELECT SUM(SALES.QUAN)*PRICES.COST FROM SALES INNER JOIN PRICES ON PRICES.T_CODE = SALES.T_CODE) AS MARCH_VALUE
LEFT JOIN PRODUCTS.CODE
GROUP BY ST.NAME;
Please help me to construct correct SQL query for this.
SELECT SUM(SALES.QUAN)*PRICES.COST FROM SALES INNER JOIN PRICES ON PRICES.T_CODE = SALES.T_CODE) AS JANUARY_VALUE
You are not getting the output that you are missing a JOIN condition on that matches the date of the sale with the date of the price. Also, you would need to move the multiplication into the aggregate function.
Putting the price inside the aggregate function allows the calculation to work correctly.
Also, I believe that your query could probably be simplified by using conditional aggregation, as follows :
SELECT
SUM(CASE WHEN S.DATE BETWEEN '01.01.2018' AND '31.01.2018' THEN S.QUAN ELSE 0 END) AS JANUARY_QUANTITY,
SUM(CASE WHEN S.DATE BETWEEN '01.01.2018' AND '31.01.2018' THEN S.QUAN * P.COST ELSE 0 END) AS JANUARY_VALUE,
SUM(CASE WHEN S.DATE BETWEEN '01.02.2018' AND '28.02.2018' THEN S.QUAN ELSE 0 END) AS FEBRUARY_QUANTITY,
SUM(CASE WHEN S.DATE BETWEEN '01.02.2018' AND '28.02.2018' THEN S.QUAN * P.COST ELSE 0 END) AS FEBRUARY_VALUE,
SUM(CASE WHEN S.DATE BETWEEN '01.03.2018' AND '31.03.2018' THEN S.QUAN ELSE 0 END) AS MARCH_QUANTITY,
SUM(CASE WHEN S.DATE BETWEEN '01.03.2018' AND '31.03.2018' THEN S.QUAN * P.COST ELSE 0 END) AS MARCH_VALUE
FROM
SALES S
LEFT JOIN PRICES P ON P.T_CODE = S.T_CODE AND P.DATE = S.DATE
With this technique, the table is scanned only once, and the results are then analyzed to feed the relevant columns in the resultset. This should efficiently replace your 6 subqueries.

SQL Query to compare 2 weeks

I've got to design a query in visual studio where I have 2 data sets.
basically it goes like this.
I want to compare this weeks call total to last week per country calling.
the only thing is last weeks calls may have come from 20 diff countries while this weeks might only have come from 15.
How can I make the query such that the 20 countries will show up for both while having "0" value in for countries that do not appear this week.
below is my query:
Select country,
Sum(Case When actstatus in (5,105) Then 1 Else 0 End) As TotalCalls,
Sum(Case When actstatus = 105 Then 1 Else 0 End) As FailedCalls
From termactivity(nolock)
INNER JOIN termconfig(NOLOCK) ON cfgterminalID = actterminalID
INNER JOIN Country (nolock) on country = cycode
Where actstatus in (5,105)
and (actTerminalDateTime BETWEEN #StartDate-7 AND #EndDate-7)
Group By country
order By country asc
When Act status = 105 it means the call was not completed and when it = 5 it means the call was successful. I am doing this to get a successful call % rate per week.
Thanks in Advance!
Apply the same logic as you did to total calls and failed calls as you did to the this week and last week.
SELECT country,
COUNT(CASE WHEN actTerminalDateTime < #StartDate THEN 1 END) [LastWeekTotalCalls],
COUNT(CASE WHEN ActStatus = 105 AND actTerminalDateTime < #StartDate THEN 1 END) [LastWeekFailedCalls],
COUNT(CASE WHEN actTerminalDateTime >= #StartDate THEN 1 END) [ThisWeekTotalCalls],
COUNT(CASE WHEN ActStatus = 105 AND actTerminalDateTime >= #StartDate THEN 1 END) [ThisWeekFailedCalls]
FROM termactivity (NOLOCK)
INNER JOIN termconfig (NOLOCK)
ON cfgterminalID = actterminalID
INNER JOIN Country (NOLOCK)
ON country = cycode
WHERE actstatus in (5,105)
AND actTerminalDateTime BETWEEN DATEADD(DAY, -7, #StartDate) AND #EndDate
GROUP BY country
ORDER BY country ASC
I've also tidied up your query slightly, for example there is no point in specifying
WHEN ActStatus IN (5, 105) ...
When your WHERE clause already limits all results to 5, 105, therefore this is a redundant predicate in your case expression
From what I understand, you want to perform separate queries for two weeks, and you want both queries to produce rows for all countries, regardless of whether all countries had any calls. To achieve this, you need to use LEFT OUTER JOINS. The below code should guarantee that every country found in the Country table has a row, even if both sums are 0.
SELECT country,
SUM(CASE WHEN actstatus IN (5,105) THEN 1 ELSE 0 END) AS TotalCalls,
SUM(CASE WHEN actstatus = 105 THEN 1 ELSE 0 END) AS FailedCalls
FROM Country (NOLOCK)
LEFT OUTER JOIN termconfig (NOLOCK) ON country = cycode
LEFT OUTER JOIN termactivity (NOLOCK) ON cfgterminalID = actterminalID
WHERE (actTerminalDateTime BETWEEN #StartDate-7 AND #EndDate-7)
GROUP BY country
ORDER BY country ASC
If this was not what you wanted, perhaps you need to clarify your question. Many others have assumed that you want to combine the results into a single query.

SQL Select Query - problem pivoting rows into columns

I have three tables in an SQL 2005 database, that I need to query and display on one row. The tables are:
MasterStock
StockID, Description
1, Plate
2, Bowl
ShopStock
ShopID, StockID, StockLevel
1,1,6
2,1,0
3,1,0
4,1,10
Sales
StockId, ShopId, SoldQuantity, transDate
1, 1, 1, 5/1/2011
1,2,1, 5/1/2011
I need to get them to show one row:
StockID, Description, 1 Sales, 1 Stock, 2 Sales, 2 Stock, 3 Sales,…
I have managed to get what somewhere with the query below:
SELECT MasterStock.StockID, MasterStock.Description,
SUM(CASE WHEN sales.shopid = 1 THEN sales.Soldquantity ELSE 0 END) AS [1 Sold],
MAX(CASE WHEN shopstock.shopid = 1 THEN shopstock.stockLevel ELSE 0 END) AS [1 Stock],
SUM(CASE WHEN sales.shopid = 2 THEN sales.Soldquantity ELSE 0 END) AS [2 Sold],
MAX(CASE WHEN shopstock.shopid = 2 THEN shopstock.stockLevel ELSE 0 END) AS [2 Stock],
SUM(CASE WHEN sales.shopid = 3 THEN sales.Soldquantity ELSE 0 END) AS [3 Sold],
MAX(CASE WHEN shopstock.shopid = 3 THEN shopstock.stockLevel ELSE 0 END) AS [3 Stock],
SUM(CASE WHEN sales.shopid = 4 THEN sales.Soldquantity ELSE 0 END) AS [4 Sold],
MAX(CASE WHEN shopstock.shopid = 4 THEN shopstock.stockLevel ELSE 0 END) AS [4 Stock]
FROM ShopStock INNER JOIN
Sales ON ShopStock.StockID = Sales.StockID AND ShopStock.shopID = Sales.ShopID
INNER JOIN MasterStock ON ShopStock.StockID = MasterStock.StockID
WHERE (sales.transdate > 1/1/2010)
GROUP BY MasterStock.StockID, MasterStock.Description
However, if there are no sales for the product it doesn’t show any stock levels. If I remove the shopID join on shopstock and sales it shows the stock levels, but reports inaccurate sales - multiplies by four (one for each shopstock record?).
I know I’m missing something here, but I’m not getting anywhere! Any help would be greatly received.
Two problems:
1) You need a LEFT OUTER JOIN between ShopStock and Sales, which will ensure that the query returns records from ShopStock even if there are no related entries in Sales. By definition, an INNER JOIN will not return records from either side of the join, if one of the sides is missing records.
2) You need to move your sales.transdate > 1/1/2010 condition to the inner join, rather than the WHERE clause. Conditions in the WHERE clause will be logically applied after any logic in the table joins. So even if you get your joins right, the where clause will filter out stock without sales because sales.transdate will appear null.
Something like this:
FROM ShopStock LEFT OUTER JOIN Sales
ON ShopStock.StockID = Sales.StockID
AND Sales.transdate > 1/1/2010
INNER JOIN // the rest of your joins here
I'm guessing you also want >= on your transdate filter as well, but that's just a hunch.
Good luck!