Join two columns as a date in sql - sql

I am currently working with a report through Microsoft Query and I ran into this problem where I need to calculate the total amount of money for the past year.
The table looks like this:
Item Number | Month | Year | Amount |
...........PAST YEARS DATA...........
12345 | 1 | 2019 | 10 |
12345 | 2 | 2019 | 20 |
12345 | 3 | 2019 | 15 |
12345 | 4 | 2019 | 12 |
12345 | 5 | 2019 | 11 |
12345 | 6 | 2019 | 12 |
12345 | 7 | 2019 | 12 |
12345 | 8 | 2019 | 10 |
12345 | 9 | 2019 | 10 |
12345 | 10 | 2019 | 10 |
12345 | 11 | 2019 | 10 |
12345 | 12 | 2019 | 10 |
12345 | 1 | 2020 | 10 |
12345 | 2 | 2020 | 10 |
How would you calculate the total amount from 02-2019 to 02-2020 for the item number 12345?

Assuming that you are running SQL Server, you can recreate a date with datefromparts() and use it for filtering:
select sum(amount)
from mytable
where
itemnumber = 12345
and datefromparts(year, month, 1) >= '20190201'
and datefromparts(year, month, 1) < '20200301'

You can use this also
SELECT sum(amount) as Amount
FROM YEARDATA
WHERE ( Month >=2 and year = '2019')
or ( Month <=2 and year = '2020')
and ItemNumber = '12345'

Related

How to get count of particular column value from total number of records and display difference in two different columns in SQL Server

I am trying to get difference between total records and a column (Is_Registered) to get Month wise matrics of how many registered in particular month and how many are pending
Actual Data
| Inserted On | IsRegistered |
+-------------+--------------+
| 10-01-2020 | 1 |
| 15-01-2020 | 1 |
| 17-01-2020 | null |
| 17-02-2020 | 1 |
| 21-02-2020 | null |
| 04-04-2020 | null |
| 18-04-2020 | null |
| 19-04-2020 | 1 |
Expected Output -As shown in actual data, out of 8 users(records) 2 are registered in Jan and 6 are not ,in February total 3 are registered i.e. Jan's 2 + Feb's 1 and 5 are not and so on
| Year | Month | Registered | Not Registered |
| -------- | -------------- | ----------- | -------------- |
| 2020 | January | 2 | 6 |
| 2020 | Feb | 3 | 5 |
| 2020 | April | 4 | 4 |
But when a new record is added with new month then it should not update previous output result e.g. After adding new record with month as May and IsReg as NULL the value for Not_Registered should be as mentioned below because the new record is added in new month.
| Year | Month | Registered | Not Registered |
| -------- | -------------- | ----------- | -------------- |
| 2020 | January | 2 | 6 |
| 2020 | Feb | 3 | 5 |
| 2020 | April | 4 | 4 |
| 2020 | May | 4 | 5 |
And if the new record has month as May and Is_Registered as 1(true) then the output should be as follows
| Year | Month | Registered | Not Registered |
| -------- | -------------- | ----------- | -------------- |
| 2020 | January | 2 | 6 |
| 2020 | Feb | 3 | 5 |
| 2020 | April | 4 | 4 |
| 2020 | May | 5 | 4 |
I managed to write a query but didn't got expected output, what changes I'll have to make in order to get expected output
select year(dateinserted) as [Year], datename(month,dateinserted) as [Month],
coalesce(sum(cast(isregistered as int)), 0) as Authenticated,
sum(case when isregistered is null then 1 else 0 end) as UnAuthenticated
from table_name where IsRegistered is not null
group by year(dateinserted), datename(month,dateinserted)
order by year(dateinserted), month(min(dateinserted));
Output I got after executing above query -
| Year | Month | Registered | Not Registered |
| -------- | -------------- | ----------- | -------------- |
| 2020 | January | 2 | 1 |
| 2020 | Feb | 1 | 1 |
| 2020 | April | 1 | 2 |
Hmmm . . . You seem to want a cumulative sum of the counts (which are 1 or NULL, so count() works). For the second column, then difference between that and the total number of rows:
select year(dateinserted) as [Year],
datename(month, dateinserted) as [Month],
count(isregistered) as registered_in_month,
sum(count(isregistered)) over (order by min(dateinserted)) as registered_up_to_month,
sum(count(*)) over () - sum(count(isregistered)) over (order by min(dateinserted)) as not_yet_registered
from table_name
group by year(dateinserted), datename(month, dateinserted)
order by year(dateinserted), month(min(dateinserted));
Here is a db<>fiddle.
You should use self join and analytical function as follows:
Select year(t.inserted_on) as yr,
datename(month, t.dateinserted) as mnth,
Sum(count(t.is_registered))
over (order by min(t.inserted_on)) as resistered,
Tt.cnt - Sum(count(t.is_registered))
over (order by min(t.inserted_on)) as not_registered
From your_table t
Join (select t.*,
Count(*) over () as cnt
From your_table t) tt on t.inserted_on = tt.inserted_on
group by year(t.dateinserted), datename(month, t.dateinserted), tt.cnt
order by year(t.dateinserted), month(min(t.dateinserted));

Group By Different Values

I would like to group by the first day and then the rest of the month, I have data that spans years.
I have data like below:
--------------------------------------
DAY MONTH YEAR VISITOR_COUNT
--------------------------------------
1 | 12 | 2014 | 16260
2 | 12 | 2014 | 15119
3 | 12 | 2014 | 14464
4 | 12 | 2014 | 13746
5 | 12 | 2014 | 13286
6 | 12 | 2014 | 14352
7 | 12 | 2014 | 19293
8 | 12 | 2014 | 13338
9 | 12 | 2014 | 13961
10 | 12 | 2014 | 9519
11 | 12 | 2014 | 10204
12 | 12 | 2014 | 9380
13 | 12 | 2014 | 11611
14 | 12 | 2014 | 14839
15 | 12 | 2014 | 10051
16 | 12 | 2014 | 8983
17 | 12 | 2014 | 7348
18 | 12 | 2014 | 7258
19 | 12 | 2014 | 7205
20 | 12 | 2014 | 6113
21 | 12 | 2014 | 5316
22 | 12 | 2014 | 6914
23 | 12 | 2014 | 6880
24 | 12 | 2014 | 6289
25 | 12 | 2014 | 6000
26 | 12 | 2014 | 13328
27 | 12 | 2014 | 10367
28 | 12 | 2014 | 7946
29 | 12 | 2014 | 9042
30 | 12 | 2014 | 9408
31 | 12 | 2014 | 8411
1 | 1 | 2015 | 9965
2 | 1 | 2015 | 10560
3 | 1 | 2015 | 9662
4 | 1 | 2015 | 8735
5 | 1 | 2015 | 12817
6 | 1 | 2015 | 13516
7 | 1 | 2015 | 9800
8 | 1 | 2015 | 10629
9 | 1 | 2015 | 12325
10 | 1 | 2015 | 11899
11 | 1 | 2015 | 11049
12 | 1 | 2015 | 13934
13 | 1 | 2015 | 16833
14 | 1 | 2015 | 13434
15 | 1 | 2015 | 13128
16 | 1 | 2015 | 14660
17 | 1 | 2015 | 11951
18 | 1 | 2015 | 10916
19 | 1 | 2015 | 14126
20 | 1 | 2015 | 16909
21 | 1 | 2015 | 16555
22 | 1 | 2015 | 14726
23 | 1 | 2015 | 14642
24 | 1 | 2015 | 13067
25 | 1 | 2015 | 11738
26 | 1 | 2015 | 15353
27 | 1 | 2015 | 17935
28 | 1 | 2015 | 14448
29 | 1 | 2015 | 15372
30 | 1 | 2015 | 16694
31 | 1 | 2015 | 16763
I would like to be able to group it like below:
--------------------------------------
DAY MONTH YEAR VISITOR_COUNT
--------------------------------------
1 | 12 | 2014 | 16260
2-31| 12 | 2014 | 309971
1 | 1 | 2015 | 9965
2-31| 1 | 2015 | 404176
Microsoft SQL Server 2016. Compatibility level: SQL Server 2005 (90)
Just use case:
select (case when min(day) = 1 then '1'
else concat(min(day), '-', max(day))
end) as day, month, year,
sum(visitor_count)
from t
group by year, month,
(case when day = 1 then 1 else 2 end);
Okay, this is a little tricky. The case in the group by and the case in the select are different. The group by just puts the days into two categories, 1 and others. The select chooses the minimum and maximum days in the month, to construct the range string.
EDIT:
Oy, SQL Server 2005 ???
Of course, you can do the same thing with + and type conversion, or using replace():
select (case when min(day) = 1 then '1'
else replace(replace('#min-#max', '#min', min(day)), '#max', max(day))
end) as day, month, year,
sum(visitor_count)
from t
group by year, month,
(case when day = 1 then 1 else 2 end);

Get data for fiscal year from table without date columns

I'm trying to create a query (purpose: manual DB testing) that would get the rows of the previous/current/next Fiscal Year and then the SUM(turnover)
Given
(1) the below table,
and
(2) Fiscal Year (FY) = March to February
When Previous FY -- Then 2 rows: 2016/1 to 2016/2
When Current FY -- Then 12 rows: from 2016/3 to 2017/2 (year/month)
When Future FY -- Then 1 row: 2017/3
+--------------+---------------+----------+
| Year (num) | Month (num) | Turnover |
+--------------+---------------+----------+
| 2016 | 1 | 1000 |
+--------------+---------------+----------+
| 2016 | 2 | 2000 |
+--------------+---------------+----------+
| 2016 | 3 | 3000 |
+--------------+---------------+----------+
| 2016 | 4 | 4000 |
+--------------+---------------+----------+
| 2016 | 5 | 2000 |
+--------------+---------------+----------+
| 2016 | 6 | 1000 |
+--------------+---------------+----------+
| 2016 | 7 | 2000 |
+--------------+---------------+----------+
| 2016 | 8 | 1000 |
+--------------+---------------+----------+
| 2016 | 9 | 2000 |
+--------------+---------------+----------+
| 2016 | 10 | 3000 |
+--------------+---------------+----------+
| 2016 | 11 | 4000 |
+--------------+---------------+----------+
| 2016 | 12 | 5000 |
+--------------+---------------+----------+
| 2017 | 1 | 6000 |
+--------------+---------------+----------+
| 2017 | 2 | 2000 |
+--------------+---------------+----------+
| 2017 | 3 | 1000 |
+--------------+---------------+----------+
The best solution I came up with is the below query and change the Year values to switch between years. It feels hacky to me because of creating an extra solumn with sysdate and checking for NOT NULL. Is there a more elegant way?
WITH CTE AS (
SELECT
CASE
WHEN Month BETWEEN 3 AND 12 AND Year = 2016
THEN sysdate
WHEN Month BETWEEN 1 AND 2 AND Year = 2017
THEN sysdate
END case_statement_date,
year, month, turnover, FROM Table
)
SELECT sum(turnover) FROM CTE
WHERE case_statement_date IS NOT NULL
;
Is this what you want?
select year + (case when month >= 3 then 0 else -1 end) as fiscal_year,
sum(turnover)
from t
group by year + (case when month >= 3 then 0 else -1 end) ;

SQL Sum divided weight over adjoining months

I have the following table (Sample):
+----+--------+-------+------+------------+
| ID | WEIGHT | MONTH | YEAR | CATEGORYID |
+----+--------+-------+------+------------+
| 1 | 0.5 | 1 | 2014 | A |
| 1 | 0.5 | 1 | 2014 | A |
| 1 | 0.5 | 2 | 2014 | A |
| 1 | 0.2 | 2 | 2014 | C |
| 1 | 0.2 | 2 | 2014 | C |
| 2 | 1.0 | 2 | 2014 | B |
| 2 | 1.0 | 2 | 2014 | B |
+----+--------+-------+------+------------+
The Output I want would be like this (Sample):
+----+--------+-------+------+------------+
| ID | WEIGHT | MONTH | YEAR | CATEGORYID |
+----+--------+-------+------+------------+
| 1 | 1.5 | 1 | 2014 | A |
| 1 | 1.5 | 2 | 2014 | A |
| 1 | 0.4 | 1 | 2014 | C |
| 1 | 0.4 | 2 | 2014 | C |
| 2 | 2.0 | 2 | 2014 | B |
| 2 | 2.0 | 3 | 2014 | B |
+----+--------+-------+------+------------+
So, when the month breaks I still want to sum the weight from previous month into the current etc. I want to sum the weight on the specific ID & CategoryID.
Hope this works.
select DISTINCT ID,sum(WEIGHT) over (partition by categoryid order by categoryid) as WEIGHT,
MONTH,YEAR, CATEGORYID
from table;
Try this
SELECT ID,
Sum(s_weight)OVER(partition BY CATEGORYID, id),
MONTH,
YEAR,
CATEGORYID
FROM (SELECT ID,
Sum(weight) AS s_weight,
MONTH,
YEAR,
CATEGORYID
FROM Yourtable
GROUP BY ID,
MONTH,
YEAR,
CATEGORYID) a

SQL group by year+month, but get months w/o records too

I want to group the content of a table by text and then by year + month and add up the count:
+-------------+---------+----------+----------+
| TEXT | T1_YEAR | T1_MONTH | T1_COUNT |
+-------------+---------+----------+----------+
| First Text | 2013 | 1 | 1 |
| First Text | 2013 | 2 | 1 |
| First Text | 2013 | 3 | 1 |
| First Text | 2013 | 5 | 1 |
| First Text | 2013 | 6 | 3 |
| First Text | 2013 | 7 | 1 |
| First Text | 2013 | 8 | 3 |
| First Text | 2013 | 9 | 1 |
| First Text | 2013 | 10 | 2 |
| Second Text | 2013 | 1 | 2 |
| Second Text | 2013 | 2 | 5 |
| Second Text | 2013 | 3 | 8 |
| Second Text | 2013 | 4 | 5 |
| Second Text | 2013 | 5 | 23 |
| Second Text | 2013 | 6 | 9 |
| Second Text | 2013 | 7 | 27 |
+-------------+---------+----------+----------+
select
table1.TEXT text,
year(table1.timestamp) t1_year,
month(table1.timestamp) t1_month,
count (*) as t1_count
from table1
group by
table1.TEXT,
year(table1.timestamp),
month(table1.timestamp)
with ur;
Now I would also like an entry in the result table for the missing months with count 0.
I have read in other threads about temporary tables, but I haven't quite figured out how to make it work.
WITH DATERANGE(LEVEL, TEMP_DATE) AS (
SELECT 1, CURRENT DATE - 5 MONTHS
FROM SYSIBM.SYSDUMMY1
UNION ALL SELECT LEVEL + 1, TEMP_DATE + 1 MONTH
FROM DATERANGE
WHERE LEVEL < 1000 AND TEMP_DATE < CURRENT DATE - 1 MONTH
) SELECT TEMP_DATE FROM DATERANGE;
Temporary date table:
+------------+
| TEMP_DATE |
+------------+
| 2013-09-05 |
| 2013-10-05 |
| 2013-11-05 |
| 2013-12-05 |
| 2014-01-05 |
+------------+
How can I achieve this easiest? I'm using DB2.
I would make a temp table with the same sort of values (year and month). Then you can outer join from that to your data table:
select
dt.theyear,
dt.themonth,
sum(t1_count)
from
DateTable DT
left outer join table1 t1
on dt.theyear = t1.t1_year
and dt.theMOnth = t1.t1_month
group by
dt.theyear,
dt.themonth
Here's a SQL Fiddle example (SQL Server, because they don't have DB2, but it should translate just fine):
SQL FIddle