I need to convert rows to column for calendar app - tsql

Probaly a simple solution to this, but it elludes me.
I have a SQL-Server (2017) table like this:
rn
wk
day
subj
1
202225
mon
subj1
2
202225
mon
subj2
3
202225
mon
subj3
1
202225
tue
subj4
2
202225
tue
subj5
1
202225
wed
subj6
2
202225
wed
subj7
1
202226
mon
subj8
2
202226
mon
subj9
1
202226
tue
subj10
1
202226
wed
subj11
2
202226
wed
subj12
3
202226
wed
subj13
I want to transpose this table to this using T-sql:
wk
mon
tue
wed
202225
subj1
subj4
subj6
202225
subj2
subj5
subj7
202225
subj3
NULL
NULL
202226
subj8
subj10
subj11
202226
subj9
NULL
subj12
202226
NULL
NULL
subj13
I tried using PIVOT, but the aggregate MAX function only gives me one record per week for the wk column. What is the correct / best SQL solution?
This is what I tried:
select * from (select wk, subj, day from mytable ) d
pivot (max(subj) for day in (mon, tue, wed, thu, fri, sat, sun)) piv;

This is just a simple pivot, or (what I and many others prefer) conditional aggregation:
SELECT wk,
MAX(CASE day WHEN 'mon' THEN subj END) AS mon,
MAX(CASE day WHEN 'tue' THEN subj END) AS tue,
MAX(CASE day WHEN 'wed' THEN subj END) AS wed
FROM (VALUES(1,202225,'mon','subj1'),
(2,202225,'mon','subj2'),
(3,202225,'mon','subj3'),
(1,202225,'tue','subj4'),
(2,202225,'tue','subj5'),
(1,202225,'wed','subj6'),
(2,202225,'wed','subj7'),
(1,202226,'mon','subj8'),
(2,202226,'mon','subj9'),
(1,202226,'tue','subj10'),
(1,202226,'wed','subj11'),
(2,202226,'wed','subj12'),
(3,202226,'wed','subj13'))V(rn,wk,day,subj)
GROUP BY rn,
wk
ORDER BY wk,
rn;
db<>fiddle

Related

Group query results by month and year in postgresql with emply month sum

Based on this answer by Burak Arslan
SELECT date_trunc('month', txn_date) AS txn_month, sum(amount) as monthly_sum
FROM yourtable
GROUP BY txn_month
Is there a way to get months that have no results to show in the query?
So let's say I have :
id transDate Product Qty
1234 04/12/2019 ABCD 2
1245 04/05/2019 ABCD 1
1231 02/07/2019 ABCD 6
I also need to the the third Month returns with a 0 value
MonthYear totalQty
02/2019 6
03/2019 0
04/2019 3
Thanks,
---- UPDATE ---
Here is the final query that that gets last 24 months from the current date. with year and month ready for any charts.
Thanks to #a_horse_with_no_name
SELECT
--ONLY USE THE NEXT LINE IF YOU NEED TO HAVE THE ID IN YOUR RESULT
CASE WHEN t."ItemId" IS NULL THEN 10607 ELSE t."ItemId" END AS "ItemId",
TO_CHAR(y."transactionDate", 'yyyy-mm-dd') AS txn_month,
TO_CHAR(y."transactionDate", 'yyyy') AS "Year",
TO_CHAR(y."transactionDate", 'Mon') AS "Month",
-coalesce(SUM(t."transactionQty"),0) AS "TotalSold"
FROM generate_series(
TO_CHAR(CURRENT_DATE - INTERVAL '24 month', 'yyyy-mm-01')::date ,
TO_CHAR(CURRENT_DATE, 'yyyy-mm-01')::date,
INTERVAL '1 month') as y("transactionDate")
LEFT JOIN "ItemTransactions" AS t
ON date_trunc('month', t."transactionDate") = y."transactionDate"
AND t."ItemTransactionTypeId" = 1
AND t."ItemId" = 10607
GROUP BY txn_month, "Year", "Month", t."ItemId"
ORDER BY txn_month ASC;
EXEMPLE OUTPUT
ItemId txn_month Year Month TotalSold
10607 2018-03-01 2018 Mar 2
10607 2018-04-01 2018 Apr 0
10607 2018-05-01 2018 May 8
10607 2018-06-01 2018 Jun 12
10607 2018-07-01 2018 Jul 6
10607 2018-08-01 2018 Aug 4
10607 2018-09-01 2018 Sep 6
10607 2018-10-01 2018 Oct 8
10607 2018-11-01 2018 Nov 4
10607 2018-12-01 2018 Dec 0
10607 2019-01-01 2019 Jan 2
10607 2019-02-01 2019 Feb 3
10607 2019-03-01 2019 Mar 4
10607 2019-04-01 2019 Apr 1
10607 2019-05-01 2019 May 4
10607 2019-06-01 2019 Jun 3
10607 2019-07-01 2019 Jul 5
10607 2019-08-01 2019 Aug 6
10607 2019-09-01 2019 Sep 6
10607 2019-10-01 2019 Oct 6
10607 2019-11-01 2019 Nov 3
10607 2019-12-01 2019 Dec 0
10607 2020-01-01 2020 Jan 4
10607 2020-02-01 2020 Feb 2
10607 2020-03-01 2020 Mar 0
Left join to a list of months:
SELECT t.txn_month,
coalesce(sum(yt.amount),0) as monthly_sum
FROM generate_series(date '2019-02-01', date '2019-04-01', interval '1 month') as t(txn_month)
left join yourtable yt on date_trunc('month', yt.transdate) = t.txn_month
GROUP BY t.txn_month
Online example
In your actual query you need to move the conditions from the WHERE clause to the JOIN condition. Putting them into the WHERE clause turns the outer join back into an inner join:
SELECT t."ItemId",
y."transactionDate" AS txn_month,
-coalesce(SUM(t."transactionQty"),0) AS "TotalSold"
FROM generate_series(date '2018-01-01', date '2020-04-01', INTERVAL '1 month') as y("transactionDate")
LEFT JOIN "ItemTransactions" AS t
ON date_trunc('month', t."transactionDate") = y."transactionDate"
AND t."ItemTransactionTypeId" = 1
AND t."ItemId" = 10606
-- this WHERE clause isn't really needed because of the date values provided to generate_series()
WHERE AND y."transactionDate" >= NOW() - INTERVAL '2 year'
GROUP BY txn_month, t."ItemId"
ORDER BY txn_month DESC;

How to sort attendance date along with the month?

Attendance is sorting according to date, that is fine, but I want to sort date along with the month name January should come at the bottom, and December at the top.
Table
Attendance Date
---------------
26 Feb 2018
19 Dec 2018
18 Dec 2018
14 Dec 2018
12 June 2018
7 Dec 2018
5 Feb 2018
Query
select distinct
(select ARRAY_TO_STRING(ARRAY_AGG(ARRAY[to_char(t1.l_time,'HH12:mi AM')]::text), ',')
from
(select (al1.create_time AT TIME ZONE 'UTC+5:30')::time as l_time
from users.access_log as al1
where al1.user_id = al.user_id
and al1.login_status = 1
and al1.create_time::date = al.create_time::date
order by al1.create_time::time ASC
) as t1
) as login_time,
(select ARRAY_TO_STRING(ARRAY_AGG(ARRAY[to_char(t2.o_time,'HH:mi AM')]::text), ',')
from
(select (al2.create_time AT TIME ZONE 'UTC+5:30')::time as o_time
from users.access_log as al2
where al2.user_id = al.user_id
and al2.login_status = 0
and al2.create_time::date = al.create_time::date
order by al2.create_time::time ASC
) as t2
) as logout_time,
al.create_time::date
from users.access_log as al
where al.user_id = ?;
Attendance is sorting according to date, that is fine, but I want to sort date along with the month name January should come at the bottom, and December at the top.

IF function to determine if SYSDATE-1 or SYSDATE-3 should be used by determining Monday

I run this report Mon-Fri for the previous day's data and I am trying to figure out how to hard code TO_CHAR(TRUNC(SYSDATE-3) if today is
Monday (day the report is run) or use TO_CHAR(TRUNC(SYSDATE-1) for any other workday (mon - fri). I am assuming that this will require an IF, THEN, ELSE statement but am unsure of how to include that properly into my query.
SELECT
RRA.LAST_MODIFICATION_DATE AS "LAST MODIFICATION DATE",
TO_CHAR(TRUNC(SYSDATE-1),'DD-MON-RR') AS "DATA_DATE"
FROM PHOENIX.R_REFERRAL_ACTIVITY RRA
Where 1=1
AND RRA.LAST_MODIFICATION_DATE
BETWEEN TO_CHAR(TRUNC(SYSDATE-1),'DD-MON-RR') AND TO_CHAR(TRUNC(SYSDATE),'DD-MON-RR')
Aha; OK then, it seems that you'd need to use CASE along with TO_CHAR function which will tell you which day is "today". Have a look, see if it helps.
TEST is just a simple calendar, several days in this February. I'm removing Saturdays and Sundays (as you said you're interested in mon - fri only).
SQL> with test as
2 (select trunc(sysdate, 'mm') + level - 1 c_date,
3 to_char(trunc(sysdate, 'mm') + level - 1, 'dy') c_day
4 from dual
5 connect by level < 20
6 )
7 select
8 c_date todays_date,
9 c_day,
10 --
11 c_date - case when c_day = 'mon' then 3
12 else 1
13 end previous_work_date,
14 --
15 to_char(c_date - case when c_day = 'mon' then 3
16 else 1
17 end, 'dy') previous_work_day
18 from test
19 where c_day not in ('sat', 'sun')
20 order by 1;
TODAYS_DAT C_D PREVIOUS_W PRE
---------- --- ---------- ---
01.02.2018 thu 31.01.2018 wed
02.02.2018 fri 01.02.2018 thu
05.02.2018 mon 02.02.2018 fri
06.02.2018 tue 05.02.2018 mon
07.02.2018 wed 06.02.2018 tue
08.02.2018 thu 07.02.2018 wed
09.02.2018 fri 08.02.2018 thu
12.02.2018 mon 09.02.2018 fri
13.02.2018 tue 12.02.2018 mon
14.02.2018 wed 13.02.2018 tue
15.02.2018 thu 14.02.2018 wed
16.02.2018 fri 15.02.2018 thu
19.02.2018 mon 16.02.2018 fri
13 rows selected.
SQL>

PostgreSQL Data Type Formatting Function

I have the following query. I need an output which would look like this
ea_month case ea_year zone_id
January 0 2013 4001
February 0 2013 4002
March 1 2013 4001
January 0 2014 4001
February 0 2014 4001
March 1 2014 4001
February 0 2014 4002
March 1 2014 4002
SELECT ea_month,CASE WHEN ea_month = (SELECT to_char(now(), 'Month')) THEN 1 ELSE 0 END,ea_year,zone_id FROM staging_ea.stg_circle_zone_billedamount_rollup
In my table I have my values for ea_month in the form of January, February, March.
After running the above query, the result-set that I am getting is something like this:
ea_month case ea_year zone_id
January 0 2013 4001
February 0 2013 4002
March 0 2013 4001
January 0 2014 4001
February 0 2014 4001
March 0 2014 4001
February 0 2014 4002
March 0 2014 4002
Can anyone suggest me where am I going wrong? Its for a PostgreSQL query.
This is caused by the to_char() function padding the month name with spaces. This can either be fixed by applying a trim() on the result or using the FM modifier in the format mask:
SELECT ea_month,
CASE
WHEN ea_month = to_char(current_date, 'FMMonth') THEN 1
ELSE 0
END,
ea_year,
zone_id
FROM staging_ea.stg_circle_zone_billedamount_rollup;
See the manual for details: http://www.postgresql.org/docs/current/static/functions-formatting.html#FUNCTIONS-FORMATTING-DATETIMEMOD-TABLE

Partitioned by Year

I have a year table like this. Every year has 12 values (Fixed)
declare #t table (FiscalYear int,[Month] varchar(25))
insert into #t values
(2011,'Jan'),(2011,'Feb'),(2011,'Mar'),(2011,'Apr'),
(2011,'May'),(2011,'Jun'),(2011,'Jul'),(2011,'Aug'),
(2011,'Sep'),(2011,'Oct'),(2011,'Nov'),(2011,'Dec'),
(2012,'Jan'),(2012,'Feb'),(2012,'Mar'),(2012,'Apr'),
(2012,'May'),(2012,'Jun'),(2012,'Jul'),(2012,'Aug'),
(2012,'Sep'),(2012,'Oct'),(2012,'Nov'),(2012,'Dec'),
(2013,'Jan'),(2013,'Feb'),(2013,'Mar'),(2013,'Apr'),
(2013,'May'),(2013,'Jun'),(2013,'Jul'),(2013,'Aug'),
(2013,'Sep'),(2013,'Oct'),(2013,'Nov'),(2013,'Dec')
I want to output as
FYear Month Qt Qtp
2011 Jan 1 1
2011 Feb 1 2
2011 Mar 1 3
2011 Apr 2 1
2011 May 2 2
2011 Jun 2 3
2011 Jul 3 1
2011 Aug 3 2
2011 Sep 3 3
2011 Oct 4 1
2011 Nov 4 2
2011 Dec 4 3
2012 Jan 1 1
2012 Feb 1 2
2012 Mar 1 3
2012 Apr 2 1
2012 May 2 2
2012 Jun 2 3
2012 Jul 3 1
2012 Aug 3 2
2012 Sep 3 3
2012 Oct 4 1
2012 Nov 4 2
2012 Dec 4 3
2013 Jan 1 1
2013 Feb 1 2
2013 Mar 1 3
2013 Apr 2 1
2013 May 2 2
2013 Jun 2 3
2013 Jul 3 1
2013 Aug 3 2
2013 Sep 3 3
2013 Oct 4 1
2013 Nov 4 2
2013 Dec 4 3
How can i do that in SQLServer2008R2. I have tried using DenseRank, RowNuber, Partitioned but all in vain.
Tru using Ntile:
--select * from #t
SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY FYear, Qt ORDER BY FYear ) Qtp
from
(SELECT FYear,[Month],
NTILE(4) OVER ( PARTITION BY FYear ORDER BY FYear ) AS Qt
FROM #t) PERIOD
ORDER BY FYear ,Qt ,ROW_NUMBER() OVER ( PARTITION BY FYear, Qt ORDER BY FYear)
I propose dynamically populating a table with date values from Dec 2013 going down to the year that you like (you can alter the #COUNT_Y Variable to add more years).
SQL has some interesting datetime functions like DATEPART which can tell you which quarter a month is in etc.
** Answer changed due to question change **
DECLARE #DATES TABLE
(
xDATE DATETIME
)
DECLARE #STARTDATE DATETIME = '12-31-2013'
DECLARE #COUNT_X INT = 0
DECLARE #COUNT_X_MAX INT = 11
DECLARE #COUNT_Y INT = 0
DECLARE #COUNT_Y_MAX INT = 2
WHILE (#COUNT_Y <= #COUNT_Y_MAX)
BEGIN
SET #COUNT_X = 0
WHILE (#COUNT_X <= #COUNT_X_MAX)
BEGIN
INSERT INTO #DATES
SELECT DATEADD(MONTH, -#COUNT_X, DATEADD(YEAR,-#COUNT_Y, #STARTDATE))
SET #COUNT_X = #COUNT_X + 1
END
SET #COUNT_Y = #COUNT_Y + 1
END
SELECT * FROM
(SELECT
DATEPART(YEAR, D.xDATE) AS [YEAR],
DATEPART(MONTH, D.xDATE) AS [MONTH],
DATENAME(MONTH, D.xDATE) AS [MONTH_NAME],
DATEPART(QUARTER, D.xDATE) AS [QUARTER],
DATEPART(MONTH, D.xDATE) - (3 * (DATEPART(QUARTER, D.xDATE) - 1)) AS [QTP]
FROM #DATES D) t
ORDER BY T.YEAR, T.MONTH