Count the number of Purchase Orders that occur within a Range - sql

I have one table (order_lines) that contains (order_lines_order_header_id) which is the PO Number and I have (order_lines.accounting_total) which is the value of the specific PO line.
I need to group the sum of each 'order_header_id' into four ranges. The first range is Purchase Orders under $500. The second is Purchase Orders between $501 and $1000. The third range between $1001 and $10,000. The forth is all POs over $10,000.
I need the results to look like this:
Count of POs under $500 -- ####
Count of POs over $501 Under $1000-- ####
Count of POs over $1,001 Under $10,000 --####
Count of POs over $10,000-- ####
Here's what I have so far but it's not working:
SELECT COUNT(order_lines.order_header_id) where SUM(order_lines.accounting_total) <= 500 as Orders_Under_500
From order_lines
Any ideas?

First, you need a subquery to calculate the total amount per order. Then you need another query to get the counts you are looking for:
select (case when total < 500 then 'Less than $500'
when total < 1000 then 'Between $500 and $1,000'
when total < 10000 then 'Between $1,000 and $10,000'
else 'Over $10,000'
end) as grp,
count(*) as Numorders
from (select ol.order_header_id, sum(accounting_total) as total
from order_lines ol
group by ol.order_header_id
) ol
group by (case when total < 500 then 'Less than $500'
when total < 1000 then 'Between $500 and $1,000'
when total < 10000 then 'Between $1,000 and $10,000'
else 'Over $10,000'
end);

Your query is not in order, the correct form would be:
SELECT COUNT(order_header_id)
FROM order_lines
WHERE SUM(accounting_total) <= 500
However, a different query is needed to select all that you need in one query:
SELECT
SUM(CASE WHEN accounting_total <500 THEN 1 ELSE 0 END) AS `500`,
SUM(CASE WHEN accounting_total BETWEEN 500 AND 1000 THEN 1 ELSE 0 END) AS `500-1000`
SUM(CASE WHEN accounting_total BETWEEN 1000 AND 10000 THEN 1 ELSE 0 END) AS `1000-10000`
SUM(CASE WHEN accounting_total >10000 THEN 1 ELSE 0 END) AS `10000`
FROM order_lines
Alternatively (not tested):
SELECT COUNT(order_header_id)
FROM order_lines
WHERE SUM(accounting_total) <= 500
OR (SUM(accounting_total) > 500 AND SUM(accounting_total) <= 1000 )
OR (SUM(accounting_total) > 1000 AND SUM(accounting_total) <= 10000 )
OR SUM(accounting_total) > 10000
GROUP BY COUNT(order_header_id)
Hope that helped.

Related

How can I count total number of sales per month using a condition in SQL?

I searched the forum but couldn't find a problem like the one I have. I have a table called Journal Table and it has the following data:
A transaction is considered to be sales if the Quantity>0 otherwise it's a loan transaction. Now my question is how can I count the total number of transactions as Sales Per month.
Like:
Month | TotalSales
1 5
2 3
3 7
I tried the following but got the wrong output:
Select DISTINCT Month(date) AS 'Month',
(Select COUNT(TransactionID) from journalTable where Quantity>0)
AS 'Total Sales' from journalTable;
Here is a picture of the output:
The output is wrong as it counts the total of all months and shows it for each month. It should count each month's total and show it.
Just group by and conditionally sum.
select Month(date) as 'Month'
, sum(case when Quantity > 0 then 1 else 0 end) as 'Total Sales'
-- You can even add a count of loans at the same time.
, sum(case when Quantity <= 0 then 1 else 0 end) as 'Total Loans'
from journalTable
group by Month(date);
Something like this
SELECT MONTH(DATE) AS MONTH, COUNT(QUANTITY)CNTT
FROM TRANSACTIONS
WHERE QUANTITY > 0
GROUP BY MONTH(DATE)

Best way to find number of account within certain value ranges

I am having trouble what would be the best/most efficient way to find all accounts that fall within a certain value range without having 20 different selects.
So for example I need to find the following:
Account Value Number of plans average value
$100-$10000
$11000-$15000
$16000-$20000
$21000-$30000
$30000+
So right now my query is basically this for every value range:
SELECT COUNT (acct) AS 'Number of Plans'
, AVG (Value) AS 'Average Value'
FROM #RT1
WHERE Value
BETWEEN 0 AND 249999.99
AND InstaCode = 'S'
and there are three different charts that needs to be populated in SSRS. The only way I can figure it out is writing 15 different select statements but i feel there should be an easier and more effective way to do this.
Thanks!
I like to use cross apply for this:
SELECT v.grp, COUNT(acct) AS num_plans, AVG(value) as avg_value
FROM #RT1 t CROSS APPLY
(VALUES (CASE WHEN value >= 100 and value < 10000 THEN '$100-$10000'
WHEN value < 15000 THEN '$11000-$15000'
WHEN value < 20000 THEN '$16000-$20000'
WHEN value < 30000 THEN '$21000-$30000'
ELSE '$30000+'
END) as grp
) v(grp)
GROUP BY v.grp;
I'm not sure what InstaCode = 'S' has to do with the results. It is easy enough to add, either to the CASE expression or to a WHERE clause.
Use conditional aggregation for each group:
SELECT COUNT (case when Value
BETWEEN 0 AND 249999.99
then value else null end) AS 'Number of Plans group 1',
COUNT (case when Value
BETWEEN 2500000 AND 3000000
then value else null end) AS 'Number of Plans group 2',
AVG (case when Value
BETWEEN 0 AND 249999.99
then value else null end) AS 'Average Value 1st group', AVG (case when Value
BETWEEN 2500000 AND 3000000
then value else null end) AS 'Average Value 2nd group'...
from #RT1
where instacode='s'
SELECT
Case
When Value between 100 and 10000 Then '100 to 10000'
When Value between 11000 and 15000 Then '11000 to 15000'
When Value between 16000 and 20000 Then '16000 to 20000'
When Value between 21000 and 30000 Then '21000 to 30000'
When Value > 30000 Then '30000+'
End as AccountValue
COUNT (acct) AS NumberofPlans
, AVG (Value) AS AverageValue
FROM #RT1
WHERE Value
BETWEEN 0 AND 249999.99
AND InstaCode = 'S'
Group by
Case
When Value between 100 and 10000 Then '100 to 10000'
When Value between 11000 and 15000 Then '11000 to 15000'
When Value between 16000 and 20000 Then '16000 to 20000'
When Value between 21000 and 30000 Then '21000 to 30000'
When Value > 30000 Then '30000+'
End

Difference between COUNT and SUM within an Aggregate CASE statement

Full disclosure, I am learning and I have searched all over the internet and I just can't figure out my question.
I am working on an online class and was given the following example:
select
DATENAME(MONTH, DATEADD(MONTH, MONTH(OrderDate), -1)) AS 'Month',
SUM(CASE WHEN YEAR(OrderDate) = 2005 THEN 1 ELSE 0 END) AS Orders,
SUM(CASE YEAR(OrderDate) WHEN 2005 THEN Totaldue ELSE 0 END) AS 'Total Value'
from
sales.salesorderheader
group by Month(orderdate)
order by Month(orderdate) ASC
That returns the following results:
I understood that (I thought) so I began messing around with the code to further understand Case statements. Looking at the code I thought that the Orders field was essentially finding all the orders in a month, assigning a 1 to each one, and then adding them all up. Because each one was assigned a 1 I figured that I could change the SUM to COUNT and I would get the same results.
However, this code:
select
DATENAME(MONTH, DATEADD(MONTH, MONTH(OrderDate), -1)) AS 'Month',
COUNT(CASE WHEN YEAR(OrderDate) = 2005 THEN 1 ELSE 0 END) AS Orders,
SUM(CASE YEAR(OrderDate) WHEN 2005 THEN Totaldue ELSE 0 END) AS 'Total Value'
from
sales.salesorderheader
group by Month(orderdate)
order by Month(orderdate) ASC
Returns these results:
To try and break this down I created a query that would just look for the orders in January 2005 and count them.
SELECT COUNT(*)
FROM Sales.SalesOrderHeader
WHERE OrderDate >= '1/1/2005' AND OrderDate < '1/1/2005'
This returned 0. The same as the SUM query. I get that COUNT counts rows and SUM sums numbers in a column, but I just don't understand the results I'm getting. Could someone please explain why the count query is returning 2483 for January and not 0?
For COUNT 1 and 0 are the same. What you really need is NULL:
COUNT(ALL expression) evaluates expression for each row in a group and returns the number of nonnull values.
select
DATENAME(MONTH, DATEADD(MONTH, MONTH(OrderDate), -1)) AS 'Month',
COUNT(CASE WHEN YEAR(OrderDate) = 2005 THEN 1 ELSE NULL END) AS Orders,
SUM(CASE YEAR(OrderDate) WHEN 2005 THEN Totaldue ELSE 0 END) AS 'Total Value'
from sales.salesorderheader
group by Month(orderdate)
order by Month(orderdate) ASC;
Or even shorter(default ELSE is NULL so we could omit that part)
COUNT(CASE WHEN YEAR(OrderDate) = 2005 THEN 1 END) AS Orders,
Example:
SUM COUNT COUNT
2005 1 1 1
2006 0 0 NULL
2007 0 0 NULL
2005 1 1 1
===============================================
2 4 2
When you use count(*) you count ALL the rows. If you want to count how many orders you have, you have to use a column: eg: count(OrderDate). Try it
count example:
assume that your column has 3 value and column name is the order
2 ---------- 5 ---------- 4----- Null
now if you run
count (order)
it will return = 3 how many entries you have in the column without null
sum example:
2 ---------- 5 ---------- 4
now if you run
sum (order)
it will return = 2+5+4=11 its add all the entries

SQL Columns Subquery with different criteria

Lets say a have two tables, [Products] and [Quantiy].
I need to select a join in both in order to built a table with total Quantity per product.
I know who to do this in a vanilla join. My problem is that i need 3 columns one [PreviewTotal] where I should have this total quantity since ever till yesterday no matter sign of quantity other [TodaytotalPos] with quantity for today and positive and other [TodaytotalNeg] only today and negative.
result like:
[Products] [PreviewTotal] [TodaytotalPos] [TodaytotalNeg]
AAPL 20,000 500 -700
MCD 15,000 NULL -300
BAC -30,000 2,000 NULL
Sample of structure:
Producst:
[id] [name]
1 AAPL
2 MCD
3 BAC
Quantity:
[date] [Id_Product] [Quantity]
12/16 1 500
12/16 2 -300
12/17 1 1,000
12/18 3 5,500
12/18 1 -2,000
Based on the rules you specify, I think you are just looking for conditional aggregation. Your query would look something like this:
select p.name,
sum(case when [date] < cast(getdate() as date) then quantity end) as PreviewTotal,
sum(case when [date] = cast(getdate() as date) and quantity > 0
then quantity end) as TodayTotalPos,
sum(case when [date] = cast(getdate() as date) and
quantity < 0 then quantity end) as TodayTotNeg
from products p join
quantity q
on q.id_product = p.id
group by p.name
order by p.name;
However, your desired results don't match the input data, based on these rules.
In SQL Server you can use CASE to select a field value if a condition is true or false. I assume your [Products] table contains at least ProductId and ProductName, and your [Quantity] table contains at least ProductId, Qty, and SoldDate.
-- get the time of midnight, the start of today:
DECLARE Today datetime;
SELECT DATEADD(DAY, DATEDIFF(DAY, '19000101', GETDATE()), '19000101') INTO Today
-- get the totals
SELECT Products.ProductName,
SUM(
CASE
WHEN Quantity.SoldDate >= Today THEN Quantity.Qty
ELSE 0
END) AS PreviewTotal,
SUM(
CASE
WHEN Quantity.Qty> 0 AND Quantity.SoldDate >= Today) THEN Quantity.Qty
ELSE 0
END) AS TodaytotalPos,
SUM(
CASE
WHEN Quantity.Qty< 0 AND Quantity.SoldDate >= Today THEN Quantity.Qty
ELSE 0
END) AS TodaytotalNeg
FROM Products JOIN Quantity on Products.ProductId = Quantity.ProductId
GROUP BY ProductName

Can I combine my two SQLite SELECT statements into one?

I have a SQLite table called posts. An example is shown below. I would like to calculate the monthly income and expenses.
accId date text amount balance
---------- ---------- ------------------------ ---------- ----------
1 2008-03-25 Ex1 -64.9 3747.56
1 2008-03-25 Shop2 -91.85 3655.71
1 2008-03-26 Benny's -100.0 3555.71
For the income I have this query:
SELECT SUBSTR(date, 0,7) "month", total(amount) "income" FROM posts
WHERE amount > 0 GROUP BY month ORDER BY date;
It works fine:
month income
---------- ----------
2007-05 4877.0
2007-06 8750.5
2007-07 8471.0
2007-08 5503.0
Now I need the expenses and I could of cause just repeat the first statement with the condition amount < 0, but I am wondering if there is an elegant way to get both income and expenses in one query?
Try something like this
select substr(date, 0,7) "Month",
total(case when a > 0 then a else 0 end) "Income",
total(case when a < 0 then a else 0 end) "Expenses"
from posts
group by month
Look into the UNION statement (bottom of the link). This will let you combine the results of two queries, generally in the form:
<SELECT_STATEMENT_1> UNION <SELECT_STATEMENT_2>
Not sure if SQL Lite supports CASE statements, but if it does you could do something like this.
SELECT SUBSTR(date, 0,7) "month"
, total(CASE WHEN Amount > 0 THEN Amount ELSE 0 END) "income"
, -1 * total(CASE WHEN Amount < 0 THEN Amount ELSE 0 END) "expenses"
FROM posts
GROUP BY month
ORDER BY date;