Sum case from previous month - sql

I couldn't find the answer to this on here or on google.
This is part of the main table
+---+-------+----------------+--------------+
| | Acct | Last_trans_date|Last_transpay |
+---+-------+----------------+--------------+
| 1 | ABC | July 31 | Nov 5 |
| 2 | DEF | Mar 1 | Aug 8 |
| 3 | GFH | Mar 9 | Feb 7 |
+---+------+-----------------+--------------+
I want the total account for the previous month that includes last_trans_date and Last_transpay = previous month as count.
I used this
Select
year(open)
sum(case when month(last_trans_date) = month(current date - 1) and month(last_transpay) = month(current_date - 1) then 1 else 0 end) as activity
from table
group by 1.
I don't think it's outputting the correct amount

SELECT Count(*)
FROM [table]
WHERE
CHARINDEX(#PrevMonth, Last_trans_date) = 1
AND CHARINDEX(#PrevMonth, Last_transpay) = 1

Related

Case statement gives unexpected output

I have a subquery producing some rows like this:
| year | quarter | id | status |
|------|---------|----|--------|
| 2020 | 4 | 1 | no |
| 2021 | 1 | 1 | yes |
| | | | |
I then want to add an extra column to track status change. I have tried this:
select
*,
case
when (year = 2020 and quarter = 4 and status = 'no') and (year = 2021 and quarter = 1 and status = 'yes')
then 1 else 0
end as status_change_during_2021_q1
from(
...
...
) t
order by id, year, quarter
limit 50
However, this is the output I get:
| year | quarter | id | status | status_change_during_2021_q1 |
|------|---------|----|--------|------------------------------|
| 2020 | 4 | 1 | no | 0 |
| 2021 | 1 | 1 | yes | 0 |
I do not understand why the second row isn't set to 1 for status_change...?
You are trying to compare values across rows. Use lag():
(case when status = 'yes' and
lag(status) over (partition by id order by year, quarter) = 'no'
then 1 else 0
end)
Your version cannot do anything useful, because, for instance, year cannot be both 2021 and 2020 in the same row.

SQL Grouping by year gives incorrect results

I am trying to summerize sales date, by month, sales region and type. The problem is, the results change when I try to group by year.
My simplified query is as follows:
SELECT
DAB700.DATUM,DAB000.X_REGION,DAB700.BELEG_ART, // the date, sales region, order type
// calculate the number of orders per month
COUNT (DISTINCT CASE WHEN MONTH(DAB700.DATUM) = 1 THEN DAB700.BELEG_NR END) as jan,
COUNT (DISTINCT CASE WHEN MONTH(DAB700.DATUM) = 2 THEN DAB700.BELEG_NR END) as feb,
COUNT (DISTINCT CASE WHEN MONTH(DAB700.DATUM) = 3 THEN DAB700.BELEG_NR END) as mar
FROM "DAB700.ADT" DAB700
left join "DAB050.ADT" DAB050 on DAB700.BELEG_NR = DAB050.ANUMMER // join to table 050, to pull in order info
left join "DF030000.DBF" DAB000 on DAB050.KDNR = DAB000.KDNR // join table 000 to table 050, to pull in customer info
left join "DAB055.ADT" DAB055 on DAB050.ANUMMER = left (DAB055.APNUMMER,6)// join table 055 to table 050, to pull in product info
WHERE (DAB700.BELEG_ART = 10 OR DAB700.BELEG_ART = 20) AND (DAB700.DATUM>={d '2021-01-01'}) AND (DAB700.DATUM<={d '2021-01-11'}) AND DAB055.ARTNR <> '999999' AND DAB055.ARTNR <> '999996' AND DAB055.TERMIN <> 'KW.22.22' AND DAB055.TERMIN <> 'KW.99.99' AND DAB050.AUF_ART = 0
group by DAB700.DATUM,DAB000.X_REGION,DAB700.BELEG_ART
This returns the following data, which is correct (manually checked):
| DATUM | X_REGION | BELEG_ART | jan | feb | mar |
|------------|----------|-----------|-----|-----|-----|
| 04.01.2021 | 1 | 10 | 3 | 0 | 0 |
| 04.01.2021 | 3 | 10 | 2 | 0 | 0 |
| 04.01.2021 | 4 | 10 | 1 | 0 | 0 |
| 04.01.2021 | 4 | 20 | 1 | 0 | 0 |
| 04.01.2021 | 6 | 20 | 2 | 0 | 0 |
| 05.01.2021 | 1 | 10 | 1 | 0 | 0 |
and so on....
The total number of records for Jan is 117 (correct).
Now I now want to summerize the data in one row (for example, data grouped by region and type)..
so I change my code so that I have:
SELECT
YEAR(DAB700.DATUM),
and
group by YEAR(DAB700.DATUM)
the rest of the code stays the same.
Now my results are:
| EXPR | X_REGION | BELEG_ART | jan | feb | mar |
|------|----------|-----------|-----|-----|-----|
| 2021 | 1 | 10 | 16 | 0 | 0 |
| 2021 | 1 | 20 | 16 | 0 | 0 |
| 2021 | 2 | 10 | 19 | 0 | 0 |
| 2021 | 2 | 20 | 22 | 0 | 0 |
| 2021 | 3 | 10 | 12 | 0 | 0 |
| 2021 | 3 | 20 | 6 | 0 | 0 |
Visually it is correct. But, the total count for January is now 116. A difference of 1. What am I doing wrong?
How can I keep the results from the first code - but have it presented as per the 2nd set?
You count distinct BELEG_NR. This is what makes the difference. Let's look at an example. Let's say your table contains four rows:
DATUM
X_REGION
BELEG_ART
BELEG_NR
04.01.2021
1
10
100
04.01.2021
1
10
200
05.01.2021
1
10
100
05.01.2021
1
10
300
That gives you per day, region and belegart:
DATUM
X_REGION
BELEG_ART
DISTINCT COUNT BELEG_NR
04.01.2021
1
10
2
05.01.2021
1
10
2
and per year, region and belegart
YEAR
X_REGION
BELEG_ART
DISTINCT COUNT BELEG_NR
2021
1
10
3
The BELEG_NR 100 never appears more than once per day, so every instance gets counted. But it appears twice for the year, so it gets counted once instead of twice.

Showing date even zero value SQL

I have SQL Query:
SELECT Date, Hours, Counts FROM TRANSACTION_DATE
Example Output:
Date | Hours | Counts
----------------------------------
01-Feb-2018 | 20 | 5
03-Feb-2018 | 25 | 3
04-Feb-2018 | 22 | 3
05-Feb-2018 | 21 | 2
07-Feb-2018 | 28 | 1
10-Feb-2018 | 23 | 1
If you can see, there are days that missing because no data/empty, but I want the missing days to be shown and have a value of zero:
Date | Hours | Counts
----------------------------------
01-Feb-2018 | 20 | 5
02-Feb-2018 | 0 | 0
03-Feb-2018 | 25 | 3
04-Feb-2018 | 22 | 3
05-Feb-2018 | 21 | 2
06-Feb-2018 | 0 | 0
07-Feb-2018 | 28 | 1
08-Feb-2018 | 0 | 0
09-Feb-2018 | 0 | 0
10-Feb-2018 | 23 | 1
Thank you in advanced.
You need to generate a sequence of dates. If there are not too many, a recursive CTE is an easy method:
with dates as (
select min(date) as dte, max(date) as last_date
from transaction_date td
union all
select dateadd(day, 1, dte), last_date
from dates
where dte < last_date
)
select d.date, coalesce(td.hours, 0) as hours, coalesce(td.count, 0) as count
from dates d left join
transaction_date td
on d.dte = td.date;

Grouping SQL results at 2 sub levels

I am using an Access front end screen and SQL queries at the back end. I am trying to get a result set that is grouped at 2 levels: Region & Month and then a relevant count of total clients active in that period, clients with orders and clients without orders all within the period selected by the user.
Below are the 2 tables in use
Client Table A
ID | Region | StartDate | Name
1 | North | 1 Jan 16 | ABC
2 | North | 1 Mar 16 | DEF
3 | East | 1 Jul 16 | GHE
4 | East | 1 Aug 16 | HIJ
5 | West | 1 Feb 16 | KLM
6 | West | 1 Mar 16 | NOP
7 | South | 1 Apr 16 | QUR
8 | South | 1 Jan 16 | STU
Orders Table B
OrderID | Client ID |Order Date
1 | 1 | 15 Mar 16
2 | 3 | 15 Jul 16
3 | 5 | 15 Jun 16
4 | 8 | 15 Jul 16
5 | 6 | 15 Jul 16
6 | 4 | 15 Jan 16
7 | 2 | 15 Feb 16
8 | 1 | 15 Jul 16
9 | 3 | 05 Aug 16
10 | 3 | 16 Jul 16
11 | 2 | 15 May 16
12 | 4 | 15 May 16
13 | 6 | 15 May 16
14 | 7 | 15 Mar 16
The User picks a start date and end date for the report for Eg 1 May 2016 to 31 Jul 16
I need a query that will evaluate if client start date is within reporting period and produce the following out put:
Result Set
Region | Month |Total Clients|Clients with Orders|Clients w/o Orders
North |May-2016| 2 | 1 | 1
North |Jun-2016| 2 | 0 | 2
North |Jul-2016| 2 | 1 | 1
East |May-2016| 0 | 0 | 0
East |Jun-2016| 0 | 0 | 0
East |Jul-2016| 1 | 1 | 0
West |May-2016| 2 | 1 | 1
West |Jun-2016| 2 | 0 | 2
West |Jul-2016| 2 | 1 | 1
South |May-2016| 2 | 0 | 2
South |Jun-2016| 2 | 0 | 2
South |Jul-2016| 2 | 1 | 1
Ive been stuck on this for 2 weeks now.. Please Help!!!
if it helps this is how far I have gotten
PARAMETERS startDt DateTime, endDt DateTime, loc Text ( 255 );
SELECT DISTINCT a.[Region] AS Region,
Format(b.[Orderdate],"MMM-YY") AS MonthOrder,
(Select Count(CMet.[clientID]) as cnt from
(SELECT distinct b.[orderID], Format(b.[order date],"MMM-YY")
as Contact_Month, a.[clientID], a.[Region]
FROM Client as a
INNER JOIN orders AS b ON a.[client ID] = b.[client id]
WHERE iif(isnull(loc),a.[REgion] like '*',instr (loc,a.[region]))
and (b.[orderdate] between startDt and endDt)
and (a.[Start date] < startDt)
GROUP BY a.[Region], Format(b.[order date],"MMM-YY"),
a.[clientID], a.[Region]
HAVING count(a.[clientID]) >=1) as CMet) AS Clients_Met,
(select count([client id]) from clients where
iif(isnull(loc),[region] like '*',instr (loc,[region])) and
client.[Start date] < startDt AS Total_Client,
(Total_Client-Clients_Met) AS Not_Met,
format(Clients_Met/iif(Total_Client =0,1,Total_Client),'##.##%') AS Met_Percentage
FROM clients AS a
INNER JOIN orders AS b ON a.[client ID]=b.[client id]
WHERE iif(isnull(loc),a.[region] like '*',instr (loc,a.[region]))
and (a.[Start date] < startDt
GROUP BY a.[region], Format(b.[order date],"MMM-YY")
HAVING count(a.[client id]) >=1
ORDER BY a.[region];
I tried the solution below. The idea is to do the grouping in the inner query, then do the summing in the outer one:
SELECT Region, Month, Count(ID) AS Clients, Sum(HasOrder) AS ClientsWithOrders,
[Clients]-[ClientsWithOrders] AS ClientsWithoutOrders
FROM (SELECT Region, CDate(Month([Order Date]) & "/1/" & Year([Order Date])) AS [Month],
ID, Max(IIf([Client ID]=[ID],1,0)) AS HasOrder
FROM Orders, Client
WHERE ((([Order Date])>=#5/1/2016# And
([Order Date])<DateAdd("d",1,#7/31/2016#)))
GROUP BY Region, CDate(Month([Order Date]) & "/1/" & Year([Order Date])), ID)
AS RegionMonthClient
GROUP BY Region, Month
The difficulty is I'm getting different results from you. For example, for East clients (3,4) I see one with an order in May (client 4) and one with an order in July (client 3).
Is this approach useful to you in any way?
You can use the join statement and to check the date use the BETWEEN operation. Here is the link for sample join statement and Between Opration.

How in query result add 0-data for don't exist rows?

I have Table with columns: "Month" and "Year", and other data.
All row in Table have different values "Month" and "Year".
But for some Month and Year rows don't exist.
I want create SQL-query (... where year in (2010, 2011, 2012) ...), that in result this SQL-query have all Month for select Year and if some month don't exist else add it to result with 0 in other data columns.
Example:
Input: Table
data / month / year
+-----+---+------+
| 3.0 | 1 | 2011 |
| 4.3 | 3 | 2011 |
| 5.7 | 4 | 2011 |
| 2.2 | 5 | 2011 |
| 5.4 | 7 | 2011 |
+-----+---+------+
Output: SELECT ... WHERE year IN (2011)
+-----+----+------+
| 3.0 | 1 | 2011 |
| 0 | 2 | 2011 |
| 4.3 | 3 | 2011 |
| 5.7 | 4 | 2011 |
| 2.2 | 5 | 2011 |
| 0 | 6 | 2011 |
| 5.4 | 7 | 2011 |
| 0 | 8 | 2011 |
| 0 | 9 | 2011 |
| 0 | 10 | 2011 |
| 0 | 11 | 2011 |
| 0 | 12 | 2011 |
+-----+----+------+
Try Partition Outer Join:
SELECT
NVL(T.DATA, 0) DATA,
F.MONTH,
T.YEAR
FROM <your_table> T
PARTITION BY(T.YEAR)
RIGHT JOIN (SELECT LEVEL MONTH FROM DUAL CONNECT BY LEVEL <= 12) F ON T.MONTH = F.MONTH
Add your WHERE clause at the end or create a view with that definition and query against it.
select datecol,
nvl(val,0),
to_char(d.date_col,'MM') month,
to_char(d.date_col,'yyyy') year
from(
select add_months('1-Jan-2011',level-1) as datecol
from dual connect by level <= 12
) d
left join(
select sum(val) as val, month, year
from your_table
group by month, year
) S
on (to_char(d.date_col,'MM') = s.month and to_char(d.date_col,'yyyy') = s.year)
select nvl(t.data, 0), x.month, nvl(t.year, <your_year>) as year
from <your_table> t,
(select rownum as month from dual connect by level < 13) x
where (t.year is null or t.year = <your_year>)
and t.month(+) = x.month
order by x.month