SQL summing the same column with different date conditions - sql

I'm using one table and am trying to sum total spend for two separate years, pulling from the same column.
Essentially I have a list of customers, and I'm trying to sum their 2018 spend, and their 2019 spend. I've tried a few different things, but I can't seem to get the "case when" function to work because once the 2018 spend condition is met and that value is populated, it won't sum for 2019, and vice versa—so I've got a total for 2018 OR 2019, but no customers are showing spend for both.
This is my query:
select *
from
(select
buyer_first_name, buyer_last_name, buyer_address_1, buyer_address_2,
buyer_address_city, buyer_address_state, buyer_address_zip, buyer_email, buyer_phone_1,
sum(case when sale_amount > 0 and year(sale_date) = 2018 then sale_amount end) as Spend18,
sum(case when sale_amount > 0 and year(sale_date) = 2019 then sale_amount end) as Spend19
from
database.table
where
sale_date between date '2018-01-01' and date '2019-10-30'
group by
buyer_first_name, buyer_last_name, buyer_address_1, buyer_address_2,
buyer_address_city, buyer_address_state, buyer_address_zip, buyer_email, buyer_phone_1)
Any idea what I'm doing wrong? Thank you!

I really doubt that your problem is with SQL syntax or a bug. Your query looks like it should be doing what you want.
The issue is that those fields are not the same for any customer in the two years. Try something like this:
select buyer_last_name
sum(case when sale_amount > 0 and year(sale_date) = 2018 then sale_amount end) as Spend18,
sum(case when sale_amount > 0 and year(sale_date) = 2019 then sale_amount end) as Spend19
from database.table
where sale_date between date '2018-01-01' and date '2019-10-30'
group by buyer_last_name;
I speculate that last names are unlikely to change. If this works, you can start adding columns back to see where the problem columns are.
This is why databases are normalized. Repeated data tends to get out of synch.

it's weird why you have such a problem and this really need to research. Frankly I would expect the same result you do. However you can bypass this by doing something like that (assuming you are using mysql):
sum(sale_amount * if(sale_amount > 0 and year(sale_date) = 2018, 1, 0)) as Spend18,
sum(sale_amount * if(sale_amount > 0 and year(sale_date) = 2019, 1, 0)) as Spend19
If all your sales are >=0 you can skip positive condition for sale amount
If this does not work, test select without grouping and see what's going on:
select sale_amount * if(sale_amount > 0 and year(sale_date) = 2018, 1, 0) as spend18,
sale_amount * if(sale_amount > 0 and year(sale_date) = 2019, 1, 0) as spend19
from your_table;

Related

How can I show the percentage of increase or decrease of visits to a page with respect to the previous year in SQL

how are you doing? I need a query in SQL that when entering the current year shows me a percentage of increase or decrease in visits to my page with respect to the previous year, if it can be better by months.
I currently have this query that shows me the number of visits per month on my page, I need to fill the Percentage column with a new query:
SELECT
FORMAT([DateTime], 'MMMM') AS [Month],
COUNT(*) AS [CounterOfVisitors],
'' AS [Percentage]
FROM
[BasicCore.VisitorCounter]
WHERE
YEAR([DateTime]) = 2023
GROUP BY
MONTH([DateTime]), FORMAT([DateTime], 'MMMM')
This is the output:
Thank you so much
You can first scan both 2022 and 2023 data,and then use conditional CASE inside sum function to see year over year comparison.
See the following code as example.
SELECT
FORMAT([DateTime], 'MMMM') AS [Month],
SUM(CASE WHEN YEAR([DateTime])=2023 THEN 1 ELSE 0 END) AS [CounterOfVisitors],
(SUM(CASE WHEN YEAR([DateTime])=2023 THEN 1 ELSE 0 END) * 1.0 / SUM( CASE WHEN YEAR([DateTime])=2022 THEN 1 ELSE 0 END) - 1.0) AS [Percentage]
FROM
[BasicCore.VisitorCounter]
WHERE
YEAR([DateTime]) in (2022,2023)
GROUP BY
MONTH([DateTime]), FORMAT([DateTime], 'MMMM')

SQL case operation

Im fairly new with sql, and been trying to solve a problem where you have a table information about orders. In this case, Im trying to use the case operation to get a monthly report on orders, so I should have a column which states the year,another one which states the month, and then I should have columns for days 1-20,21-22,23-24 and above 25. Im trying to use the case operation to get the amount of orders that happened on those days.
I tried the following query :
SELECT
DATEPART(YEAR,date) AS year,DATEPART(MONTH,date) AS month,
COUNT(CASE WHEN DATEPART(DAY,date) BETWEEN 1 AND 20 THEN order ELSE 0 END) AS D1_D20,
COUNT(CASE WHEN DATEPART(DAY,date) BETWEEN 21 AND 22 THEN order ELSE 0 END) AS D21_D22,
COUNT(CASE WHEN DATEPART(DAY,date) BETWEEN 23 AND 24 THEN order ELSE 0 END) AS D23_D24,
COUNT(CASE WHEN DATEPART(DAY,date) > 25 THEN order ELSE 0 END) AS D25_END
FROM ORDERS
GROUP BY DATEPART(YEAR,date),DATEPART(MONTH,date)
Obviously the problem with that query is that, now I just get the total number of orders for each of the days, I know I should count the orders, but dont know the syntax. Help would be greatly appreciated!
Use SUM():
SELECT
DATEPART(YEAR, date) AS year, DATEPART(MONTH, date) AS month,
SUM(CASE WHEN DATEPART(DAY,date) BETWEEN 1 AND 20 THEN 1 ELSE 0 END) AS D1_D20,
SUM(CASE WHEN DATEPART(DAY,date) BETWEEN 21 AND 22 THEN 1 ELSE 0 END) AS D21_D22,
SUM(CASE WHEN DATEPART(DAY,date) BETWEEN 23 AND 24 THEN 1 ELSE 0 END) AS D23_D24,
SUM(CASE WHEN DATEPART(DAY,date) > 25 THEN 1 ELSE 0 END) AS D25_END
FROM ORDERS
GROUP BY DATEPART(YEAR, date), DATEPART(MONTH, date);
I would recommend using the functions DAY(), YEAR(), and MONTH() because they are simpler to type.
By the way, you can use COUNT() if you remove the ELSE clause. Your particular problem is that COUNT(0) = COUNT(1) because COUNT() counts non-NULL values. I prefer SUM() because it is more intuitive in this respect.

nest queries and pass their results as alias to SUM

So, I'm running two queries that returns me the X amount of items per month through a year.
the 1st query gives me the following result
the 'no column name' would be the months, so I have no data in august, november and december.
The second query, gives me the following
only August and Setpember has data.
What I'm trying to figure out is how can I sum both tables to get the 100% value, then define each % (corretivas x preventivas).
In my research, I assume I have to nest the queries, but I just can't reach the logic to get me near the wanted result.
this is my queries so far
select month(workOrderDate), COUNT(*) as preventivas from WorkOrder WHERE
workOrderDescription = 'preventiva'
AND YEAR(workOrderDate) = 2018
AND lastUpdateData IS NOT NULL
AND WorkType = '02'
group BY MONTH(workOrderDate)
ORDER BY MONTH(workOrderDate)
select MONTH(workOrderDate), COUNT(*) AS corretivas from WorkOrder WHERE
YEAR(workOrderDate) = 2018
AND workOrderDescription = 'CORRETIVA'
AND lastUpdateData IS NOT NULL
GROUP BY MONTH(workOrderDate)
ORDER BY MONTH(workOrderDate)
The expected result would be
and so on
Would anybody helpe me with this?
You want conditional aggregation :
SELECT MONTH(wo.workOrderDate), COUNT(*) AS total,
(SUM(CASE WHEN wo.WorkType = '02' AND wo.orkOrderDescription = 'preventiva' THEN 1 ELSE 0 END) * 1.0 / COUNT(*)) * 100 AS preventiva,
(SUM(CASE WHEN wo.orkOrderDescription = 'CORRETIVA' THEN 1 ELSE 0 END) * 1.0 / COUNT(*)) * 100 AS CORRETIVA
FROM WorkOrder wo
WHERE YEAR(wo.workOrderDate) = 2018 AND wo.lastUpdateData IS NOT NULL
GROUP BY MONTH(wo.workOrderDate);

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

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;