Sqlite pviot Add a count row with totals - sqlite

I am sure first time this question is been asked in this group.
Using sqlite i would like to do pivot display with total count in each row bottom. And i am able to do pivot table but total count is failed to do so .
CURRENT SQL QUERY:
SELECT
number as no,
outl as name,
(CASE WHEN week = "WEEK1" THEN sunday ELSE 0 END) AS WK1S,
(CASE WHEN week = "WEEK1" THEN monday ELSE 0 END) AS WK1M,
(CASE WHEN week = "WEEK1" THEN tuesday ELSE 0 END) AS WK1T,
(CASE WHEN week = "WEEK1" THEN wednesday ELSE 0 END) AS WK1W,
(CASE WHEN week = "WEEK1" THEN thursday ELSE 0 END) AS WK1T,
(CASE WHEN week = "WEEK1" THEN saturday ELSE 0 END) AS WK1SA,
(CASE WHEN week = "WEEK2" THEN sunday ELSE 0 END) AS WK2S,
(CASE WHEN week = "WEEK2" THEN monday ELSE 0 END) AS WK21M,
(CASE WHEN week = "WEEK3" THEN sunday ELSE 0 END) AS WK3S,
(CASE WHEN week = "WEEK3" THEN monday ELSE 0 END) AS WK3M,
(CASE WHEN week = "WEEK3" THEN tuesday ELSE 0 END) AS WK3T,
(CASE WHEN week = "WEEK3" THEN wednesday ELSE 0 END) AS WK3W,
(CASE WHEN week = "WEEK3" THEN thursday ELSE 0 END) AS WK3T,
(CASE WHEN week = "WEEK3" THEN saturday ELSE 0 END) AS WK3SA
FROM labels51 group by number
CURRENT OUTPUT
Expected: on bottom i need total count of each row like case when WK1S = sunday then count(WK1S) and case when WK1M = monday then count (WK1M) .... ..

try this
SELECT
number as no,
outl as name,
(CASE WHEN week = "WEEK1" THEN sunday ELSE 0 END) AS WK1S,
(CASE WHEN week = "WEEK1" THEN monday ELSE 0 END) AS WK1M,
(CASE WHEN week = "WEEK1" THEN tuesday ELSE 0 END) AS WK1T,
(CASE WHEN week = "WEEK1" THEN wednesday ELSE 0 END) AS WK1W,
(CASE WHEN week = "WEEK1" THEN thursday ELSE 0 END) AS WK1T,
(CASE WHEN week = "WEEK1" THEN saturday ELSE 0 END) AS WK1SA,
(CASE WHEN week = "WEEK2" THEN sunday ELSE 0 END) AS WK2S,
(CASE WHEN week = "WEEK2" THEN monday ELSE 0 END) AS WK21M,
(CASE WHEN week = "WEEK3" THEN sunday ELSE 0 END) AS WK3S,
(CASE WHEN week = "WEEK3" THEN monday ELSE 0 END) AS WK3M,
(CASE WHEN week = "WEEK3" THEN tuesday ELSE 0 END) AS WK3T,
(CASE WHEN week = "WEEK3" THEN wednesday ELSE 0 END) AS WK3W,
(CASE WHEN week = "WEEK3" THEN thursday ELSE 0 END) AS WK3T,
(CASE WHEN week = "WEEK3" THEN saturday ELSE 0 END) AS WK3SA
FROM labels51
UNION all
SELECT "GRAND TOTAL",
NULL ,
COUNT(CASE WHEN week = "WEEK1" AND sunday LIKE "%sunday%" THEN 1 END) AS WK1S,
COUNT(CASE WHEN week = "WEEK1" AND monday LIKE "%monday%" THEN 1 END) AS WK1M,
COUNT(CASE WHEN week = "WEEK1" AND tuesday LIKE "%tuesday%" THEN 1 END) AS WK1T,
COUNT(CASE WHEN week = "WEEK1" AND wednesday LIKE "%wednesday%" THEN 1 END) AS WK1W,
COUNT(CASE WHEN week = "WEEK1" AND thursday LIKE "%thursday%" THEN 1 END) AS WK1T,
COUNT(CASE WHEN week = "WEEK1" AND saturday LIKE "%saturday%" THEN 1 END) AS WK1SA,
COUNT(CASE WHEN week = "WEEK2" AND sunday LIKE "%sunday%" THEN 1 END) AS WK2S,
COUNT(CASE WHEN week = "WEEK2" AND monday LIKE "%monday%" THEN 1 END) AS WK2M,
COUNT(CASE WHEN week = "WEEK1" AND sunday LIKE "%sunday%" THEN 1 END) AS WK3S,
COUNT(CASE WHEN week = "WEEK3" AND monday LIKE "%monday%" THEN 1 END) AS WK3M,
COUNT(CASE WHEN week = "WEEK3" AND tuesday LIKE "%tuesday%" THEN 1 END) AS WK3T,
COUNT(CASE WHEN week = "WEEK3" AND wednesday LIKE "%wednesday%" THEN 1 END) AS WK3W,
COUNT(CASE WHEN week = "WEEK3" AND thursday LIKE "%thursday%" THEN 1 END) AS WK3T,
COUNT(CASE WHEN week = "WEEK3" AND saturday LIKE "%saturday%" THEN 1 END) AS WK3SA
FROM labels51

Related

How to use case statement with group by?

Assume our company has multiple marketing campaigns for one specific product, which might boost the sales of it in certain way. The results of the campaign are shown in the following data table:
Date CampaignID QtySold
2017-01-05 1 20
2017-01-18 2 35
2017-01-23 1 15
…
For modeling purposes, the desired output table looks like this:
CampaignID JanQtySold FebQtySold … DecQtySold
1 55 30
2 45 20
…
N
I have tried to get the month of each transaction for each campaign, and then group by campaignID and month.
select
campaignid,
strftime('%m',date) as Month,
sum(qtysold) as Sum_Qty
from campaign
group by campaignid, month
;
The return should include a unique CampaignID but I don't know how to proceed.
I believe that you want something like :-
select
campaignid,
coalesce(
(
SELECT sum(qtysold) FROM campaign AS c2 WHERE campaign.campaignid = c2.campaignid AND CAST(strftime("%m",date) AS INTEGER) = 1
)
,0) AS JanQtySold,
coalesce(
(
SELECT sum(qtysold) FROM campaign AS c2 WHERE campaign.campaignid = c2.campaignid AND CAST(strftime("%m",date) AS INTEGER) = 2
)
,0) As FebQtySold,
coalesce(
(
SELECT sum(qtysold) FROM campaign AS c2 WHERE campaign.campaignid = c2.campaignid AND CAST(strftime("%m",date) AS INTEGER) = 3
)
,0) As MarQtySold
/* .............. and so on ..........*/
from campaign
group by campaignid
;
That is introducing more groups is not really what you want for more derived columns (introducing more grouping components will introduce more rows, so you only want the 1 grouping component i.e. the campaign id). Rather you want to use sub-queries to generate the data for the derived columns.
Note for brevity only 3 months (Jan-Mar) have been shown, the other months is just a matter of copying one of the months and then amending the test value and the column name respectively.
Example :-
Using :-
DROP TABLE IF EXISTS campaign;
CREATE TABLE IF NOT EXISTS campaign (Date TEXT, CampaignID INTEGER, QtySold INTEGER);
INSERT INTO campaign VALUES
('2017-01-05',1,20),('2017-01-23',1,15),('2017-02-01',1,5),
('2017-01-18',2,35)
;
select
campaignid,
coalesce(
(
SELECT sum(qtysold) FROM campaign AS c2 WHERE campaign.campaignid = c2.campaignid AND CAST(strftime("%m",date) AS INTEGER) = 1
)
,0) AS JanQtySold,
coalesce(
(
SELECT sum(qtysold) FROM campaign AS c2 WHERE campaign.campaignid = c2.campaignid AND CAST(strftime("%m",date) AS INTEGER) = 2
)
,0) As FebQtySold,
coalesce(
(
SELECT sum(qtysold) FROM campaign AS c2 WHERE campaign.campaignid = c2.campaignid AND CAST(strftime("%m",date) AS INTEGER) = 3
)
,0) As MarQtySold
from campaign
group by campaignid
;
results in :-
You need conditional aggregation with a CASE statement inside SUM():
select
CampaignID,
sum(case strftime('%m',Date) when '01' then QtySold else 0 end) as JanQtySold,
sum(case strftime('%m',Date) when '02' then QtySold else 0 end) as FebQtySold,
sum(case strftime('%m',Date) when '03' then QtySold else 0 end) as MarQtySold,
sum(case strftime('%m',Date) when '04' then QtySold else 0 end) as AprQtySold,
sum(case strftime('%m',Date) when '05' then QtySold else 0 end) as MayQtySold,
sum(case strftime('%m',Date) when '06' then QtySold else 0 end) as JunQtySold,
sum(case strftime('%m',Date) when '07' then QtySold else 0 end) as JulQtySold,
sum(case strftime('%m',Date) when '08' then QtySold else 0 end) as AugQtySold,
sum(case strftime('%m',Date) when '09' then QtySold else 0 end) as SepQtySold,
sum(case strftime('%m',Date) when '10' then QtySold else 0 end) as OctQtySold,
sum(case strftime('%m',Date) when '11' then QtySold else 0 end) as NovQtySold,
sum(case strftime('%m',Date) when '12' then QtySold else 0 end) as DecQtySold
from campaign
where strftime('%Y',Date) = '2017'
group by CampaignID
I added the condition:
where strftime('%Y',Date) = '2017'
just in case there are rows in the table for multiple years.
If you don't want zeros in the results just remove all else 0 from the case statements.
See the demo.
Just to make it more efficient, you can a use a CTE:
with cte as (
select
CampaignID,
strftime('%Y',Date) as year,
strftime('%m',Date) as month,
QtySold
from campaign
)
select
CampaignID,
sum(case month when '01' then QtySold else 0 end) as JanQtySold,
sum(case month when '02' then QtySold else 0 end) as FebQtySold,
sum(case month when '03' then QtySold else 0 end) as MarQtySold,
sum(case month when '04' then QtySold else 0 end) as AprQtySold,
sum(case month when '05' then QtySold else 0 end) as MayQtySold,
sum(case month when '06' then QtySold else 0 end) as JunQtySold,
sum(case month when '07' then QtySold else 0 end) as JulQtySold,
sum(case month when '08' then QtySold else 0 end) as AugQtySold,
sum(case month when '09' then QtySold else 0 end) as SepQtySold,
sum(case month when '10' then QtySold else 0 end) as OctQtySold,
sum(case month when '11' then QtySold else 0 end) as NovQtySold,
sum(case month when '12' then QtySold else 0 end) as DecQtySold
from cte
where year = '2017'
group by CampaignID
See the demo.
Results:
| CampaignID | JanQtySold | FebQtySold | MarQtySold | AprQtySold | MayQtySold | JunQtySold | JulQtySold | AugQtySold | SepQtySold | OctQtySold | NovQtySold | DecQtySold |
| ---------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- |
| 1 | 35 | 65 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 35 | 75 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |

ORACLE: Range between Weeks

How would one create my expected results. Any help would be appreciated, Thanks in advance!
Master Calendar:
SELECT DISTINCT
--CA.CALENDAR_DATE,
TO_CHAR(CALENDAR_DATE,'MM/DD/YYYY') AS CALENDAR_DATE
TO_CHAR(NEXT_DAY(CALENDAR_DATE, 'Monday') - 7, 'MM/DD/YY-') ||
TO_CHAR(NEXT_DAY(CALENDAR_DATE, 'Monday') - 1, 'MM/DD/YY') AS WEEK_OF_YEAR,
ROW_NUMBER () OVER ( ORDER BY CALENDAR_DATE) AS MasterCalendar_RNK
FROM CALENDAR CA
WHERE 1=1
--AND CA.CALENDAR_DATE BETWEEN ADD_MONTHS(TRUNC(SYSDATE), -12) AND TRUNC(SYSDATE)
--AND CA.CALENDAR_DATE BETWEEN TRUNC(SYSDATE) -5 AND TRUNC(SYSDATE)
ORDER BY TO_DATE(CALENDAR_DATE,'MM/DD/YYYY') DESC
Input:
Member StartDate EndDate
A 1/31/17
B 2/1/17 2/15/17
Expected Results:
Member StartDate EndDate Week_Of_Year Active
A 1/31/17 1/30/17-2/5/17 1
A 1/31/17 2/6/17-2/12/17 1
A 1/31/17 2/13/17-2/19/17 1
B 2/1/17 2/15/17 1/30/17/2/5/17 1
B 2/1/17 2/15/17 2/6/17-2/12/17 1
B 2/1/17 2/15/17 2/13/17-2/19/17 1

R assign week value for a range of numbers

I have a data frame that looks like this:
dataset <- data.frame(date = seq(from=as.Date("2015-07-06"),
to=as.Date("2015-07-15"),by="day"),
stringsAsFactors=F)
My objective is to assign a week value to a sequence first 5 dates so it looks something like this:
date week
1: 2015-07-06 Week 1
2: 2015-07-07 Week 1
3: 2015-07-08 Week 1
4: 2015-07-09 Week 1
5: 2015-07-10 Week 1
6: 2015-07-11 Week 2
7: 2015-07-12 Week 2
8: 2015-07-13 Week 2
9: 2015-07-14 Week 2
10: 2015-07-15 Week 2
My data is only week day data, hence it's only 5 days. Each week starts from a Monday ...just to give some context.
Is there a way to do this besides counting first 5 and assigning "Week 1", then counting the next 5 and assigning "Week 2"...and so on?
I'm putting this piece in a for loop so I'm hoping for a straighforward solution.
Thank you very much!
As the 'date' column have only week days and without any breaks, we can use gl/paste to create week index. This doesn't depend on the nrow of the dataset i.e. even if the nrow is not a multiple of 5, it will work.
dataset$week <- paste('Week', as.numeric(gl(nrow(dataset),5, nrow(dataset))))
Other option would be using format after converting the 'date' column to 'Date' class.
format(as.Date(dataset$date),'%W')
#[1] "27" "27" "27" "27" "27" "27" "27" "28" "28" "28"
Or
week(strptime(dataset$date,format='%Y-%m-%d'))
#[1] 27 27 28 28 28 28 28 28 28 29
but, I am not sure that is what you wanted.
Here is my solution withe the week function of the lubridate package. Note that before passing to the week function column date need to be converted with ymd as a POSIX class.
library(lubridate)
dataset$date <- ymd(dataset$date)
dataset$week <- week(dataset$date)
dataset
date week
1 2015-07-06 27
2 2015-07-07 27
3 2015-07-08 28
4 2015-07-09 28
5 2015-07-10 28
6 2015-07-11 28
7 2015-07-12 28
8 2015-07-13 28
9 2015-07-14 28
10 2015-07-15 29
Here's a simple solution using base R:
nweeks <- 10 #choose as required
days <- paste0("Week",rep(seq(nweeks),each=5))
#> days
# [1] "Week1" "Week1" "Week1" "Week1" "Week1" "Week2" "Week2" "Week2" "Week2" "Week2" "Week3" "Week3" "Week3" "Week3" "Week3"
#[16] "Week4" "Week4" "Week4" "Week4" "Week4" "Week5" "Week5" "Week5" "Week5" "Week5" "Week6" "Week6" "Week6" "Week6" "Week6"
#[31] "Week7" "Week7" "Week7" "Week7" "Week7" "Week8" "Week8" "Week8" "Week8" "Week8" "Week9" "Week9" "Week9" "Week9" "Week9"
#[46] "Week10" "Week10" "Week10" "Week10" "Week10"

Can an SQL alias be a function? (PL/SQL)

I'm making a daily report that will produce a value for the next 7 days as such:
select
a.itemnumber
,sum(case when a.activitydate = trunc(sysdate) then a.qtyordered else 0 end) as Today
,sum(case when a.activitydate = trunc(sysdate) + 1 then a.qtyordered else 0 end) as Tomorrow
,sum(case when a.activitydate = trunc(sysdate) + 2 then a.qtyordered else 0 end) as Day3
,sum(case when a.activitydate = trunc(sysdate) + 3 then a.qtyordered else 0 end) as Day4
,sum(case when a.activitydate = trunc(sysdate) + 4 then a.qtyordered else 0 end) as Day5
,sum(case when a.activitydate = trunc(sysdate) + 5 then a.qtyordered else 0 end) as Day6
,sum(case when a.activitydate = trunc(sysdate) + 6 then a.qtyordered else 0 end) as Day7
,a.balanceonhand BOH
from
mytable a
where
a.itemnumber between 14000 and 15000
These aliases are more ambiguous than I would like, and especially if the user compares reports from one day to another, these mean nothing. Using PL/SQL Developer, can I make an alias that will produce a variable date? I tried the following code:
select
a.itemnumber
,sum(case when a.activitydate = trunc(sysdate) then a.qtyordered else 0 end) as sysdate
,sum(case when a.activitydate = trunc(sysdate) + 1 then a.qtyordered else 0 end) as sysdate + 1
,sum(case when a.activitydate = trunc(sysdate) + 2 then a.qtyordered else 0 end) as sysdate + 2
,sum(case when a.activitydate = trunc(sysdate) + 3 then a.qtyordered else 0 end) as sysdate + 3
,sum(case when a.activitydate = trunc(sysdate) + 4 then a.qtyordered else 0 end) as sysdate + 4
,sum(case when a.activitydate = trunc(sysdate) + 5 then a.qtyordered else 0 end) as sysdate + 5
,sum(case when a.activitydate = trunc(sysdate) + 6 then a.qtyordered else 0 end) as sysdate + 6
,a.balanceonhand BOH
from
mytable a
where
a.itemnumber between 14000 and 15000
group by
a.itemnumber
,a.balanceonhand
But it says the FROM keyword not found where expected. Is this possible?
It would be easier if you use a row generator to get your seven dates (or indeed any number of dates). This will provide the data in row based format.
From there I suggest PIVOT is a good way to reformat the output into columns rather than rows. I've provided an 'offset' column in the dategen query so that this can be added to the startdate which, in this case, is a sqlplus variable but I'd suggest using a bind variable in the production query. I'd strongly recommend against using SYSDATE as this makes things very hard to test. It's easier when you can change the dates covered by the report to suit available test data.
1 WITH
2 dategen
3 as
4 (
5 SELECT TO_DATE('&startdate','DD-MON-YYYY')+LEVEL mydate, LEVEL myoffset
6 FROM dual
7 CONNECT BY LEVEL <=7)
8 SELECT itemnumber,balanceonhand, activitydate, today, tomorrow, day3, day4, day5, day6, day7
9 FROM (
10 SELECT *
11 FROM mytable t
12 JOIN dategen d ON (d.mydate = t.activitydate)
13 PIVOT (
14 SUM(qtyordered)
15 FOR myoffset IN (0 as today,1 as tomorrow,2 day3,3 as day4, 4 as day5, 5 as day6, 6 as day7)
16* ))
SQL> /
Enter value for startdate: 01-JAN-2015
old 5: SELECT TO_DATE('&startdate','DD-MON-YYYY')+(level-1) mydate, LEVEL myoffset
new 5: SELECT TO_DATE('01-JAN-2015','DD-MON-YYYY')+(level-1) mydate, LEVEL myoffset
ITEMNUMBER BALANCEONHAND ACTIVITYDATE TODAY TOMORROW DAY3 DAY4 DAY5 DAY6 DAY7
120 100 02-JAN-15 10
140 100 04-JAN-15 10
100 100 02-JAN-15 10
3 rows selected.
SQL> select * from mytable;
ITEMNUMBER BALANCEONHAND ACTIVITYDATE QTYORDERED
---------- ------------- ------------------ ----------
100 100 02-JAN-15 10
120 100 02-JAN-15 10
140 100 04-JAN-15 10
3 rows selected.

Get Current Monday?

I have this string that is a date called strRDate and another string called strColor.
The cutoff date is this weeks Monday.
I would like to be something like this:
'// strRDate format is MM/DD/YYYY
Dim strRDate,strColor
strRDate="1/1/1999"
strColor="none"
If strRDate is this weeks Monday or older then <-- HOW DO I DO THIS ???
strColor="green"
else
strColor="red"
end if
So anything older then Oct 21, 2013 would be green, else it would be red.
' for successful parsing of mm/dd/yyyy dates (1033 is EN_US)
Response.LCID = 1033
Dim strRDate, strColor
strRDate = "10/21/2013"
strColor = GetColor(ParseDate(strRDate))
and a few helper functions:
Function GetColor(d)
GetColor = "none"
If IsDate(d) Then
If d <= GetMondayForWeek(Now()) Then
GetColor = "green"
Else
GetColor = "red"
End If
End If
End Function
Function ParseDate(strDate)
ParseDate = vbEmpty
If IsDate(strDate) Then
ParseDate = CDate(strDate)
End If
End Function
Function GetMondayForWeek(d)
' midnight
GetMondayForWeek = CDate(Fix(d))
While Weekday(GetMondayForWeek) <> vbMonday
GetMondayForWeek = GetMondayForWeek - 1
Wend
End Function
I'd probably do the calculation like this:
strRDate = "1/1/1999"
strColor = "none"
monday = Date - (Weekday(Date, vbMonday) - 1)
If CDate(strRDate) <= monday Then
strColor="green"
Else
strColor="red"
End If
Weekday(Date, vbMonday) returns a value between 1 and 7 for each day of the week, with Monday being the first day:
Monday → 1
Tuesday → 2
Wednesday → 3
Thursday → 4
Friday → 5
Saturday → 6
Sunday → 7
Subtract 1 from the return value of the function and you get the difference in days between the current date and the most recent Monday. Subtracting that difference from the current date gives you the date of the most recent Monday, which you can then compare to your input date (use the CDate function to convert the string to an actual date).
This date's monday can be calculated by substracting the Weekday() and adjusting for the Weekday of mondays:
WScript.Echo "german locate (dd.mm.yyyy):"
Dim dtCur : dtCur = #10/10/2013#
Do Until dtCur > #10/24/2013#
Dim dtThisMonday : dtThisMonday = DateAdd("d", -WeekDay(dtCur) + 2, dtCur)
Dim isAfterThisMonday : isAfterThisMonday = dtCur > dtThisMonday
WScript.Echo dtCur, WeekDay(dtCur), WeekdayName(WeekDay(dtCur), True), dtThisMonday, CStr(isAfterThisMonday)
dtCur = DateAdd("d", 1, dtCur)
Loop
output:
german locate (dd.mm.yyyy):
10.10.2013 5 Thu 07.10.2013 True
11.10.2013 6 Fri 07.10.2013 True
12.10.2013 7 Sat 07.10.2013 True
13.10.2013 1 Sun 14.10.2013 False
14.10.2013 2 Mon 14.10.2013 False
15.10.2013 3 Tue 14.10.2013 True
16.10.2013 4 Wed 14.10.2013 True
17.10.2013 5 Thu 14.10.2013 True
18.10.2013 6 Fri 14.10.2013 True
19.10.2013 7 Sat 14.10.2013 True
20.10.2013 1 Sun 21.10.2013 False
21.10.2013 2 Mon 21.10.2013 False
22.10.2013 3 Tue 21.10.2013 True
23.10.2013 4 Wed 21.10.2013 True
24.10.2013 5 Thu 21.10.2013 True

Resources