MySQL - Grouping dayname() for unique columns - sql

I have a stored procedure that takes data from multiple tables. The stored procedure is called from a PHP script and the resulting data is placed in a grid.
The issue I'm having is I'm not sure how to get the dayname to be unique so that at maximum there are seven columns, one for each day of the week, as opposed to getting results like 'Tuesday' and 'Tuesday1'
Here is a snippet
select concat(
'select tbl_kiosks.name "DCI ERP",tbl_retailers.abbr "Retailer",
tbl_retaillocations.storeNumber "Store",
tbl_retaillocations.city "City",
tbl_retaillocations.state "State"'
, group_concat(
concat(',sum(if(ks.StartDate="',ks3.StartDate,'", numOfSessions, null)) "', dayname(DATE_FORMAT(ks3.StartDate,'%Y-%m-%d')) ,'" '
)
separator ' '
)

Somewhere in your group_concat, you have to select distinct dayname(...) instead of select dayname(...). That would give you only one column of each day.
Or you could consider a group by:
select
tbl_kiosks.name "DCI ERP"
, tbl_retailers.abbr "Retailer"
, tbl_retaillocations.storeNumber "Store"
, tbl_retaillocations.city "City"
, tbl_retaillocations.state "State"
, dayname(ks3.StartDate) "Weekday"
, sum(case when dayname(ks3.StartDate) = 'Monday'
then numOfSessions else 0 end) as Monday
, sum(case when dayname(ks3.StartDate) = 'Tuesday'
then numOfSessions else 0 end) as Tuesday
, ....
from <your join list here>
group by "DCI ERP", Retailer, Store, City, State, dayname(ks3.StartDate)

Related

Total customer per reporting date without union

I would like to display to run this report where I show the total number of customers per reporting date. Here is a how I need the data to look like:
My original dataset look like this (please see query): In order to calculate the number of customers. I need to use the start and end date: if Start_Date>reporting_date and End_Date<=reporting_date then count as a customer.
I was able to develop a script, but it only gives me the total number of customers for only one reporting date.
select '2022-10-31' reporting_date, count(case when Start_Date>'2022-10-31' and End_Date<='2022-10-31' then Customer_ID end)
from (values ('2022-10-14','2022-8-19','0010Y654012P6KuQAK')
, ('2022-3-15','2022-9-14','0011v65402PoSpVAAV')
, ('2021-1-11','2022-10-11','0010Y654012P6DuQAK')
, ('2022-12-1','2022-5-14','0011v65402u7muLAAQ')
, ('2021-1-30','2022-3-14','0010Y654012P6DuQAK')
, ('2022-10-31','2022-2-14','0010Y654012P6PJQA0')
, ('2021-10-31','US','0010Y654012P6PJQA0')
, ('2021-5-31','2022-5-14','0011v65402x8cjqAAA')
, ('2022-6-2','2022-1-13','0010Y654016OqkJQAS')
, ('2022-1-1','2022-11-11','0010Y654016OqIaQAK')
) a(Start_Date ,End_Date ,Customer_ID)
Is there a way to amend the code with cross-join or other workarounds to the total customers per reporting date without doing many unions
select '2022-10-31' reporting_date, count(case when Start_Date>'2022-10-31' and End_Date<='2022-10-31' then Customer_ID end)
from (values ('2022-10-14','2022-8-19','0010Y654012P6KuQAK')
, ('2022-3-15','2022-9-14','0011v65402PoSpVAAV')
, ('2021-1-11','2022-10-11','0010Y654012P6DuQAK')
, ('2022-12-1','2022-5-14','0011v65402u7muLAAQ')
, ('2021-1-30','2022-3-14','0010Y654012P6DuQAK')
, ('2022-10-31','2022-2-14','0010Y654012P6PJQA0')
, ('2021-10-31','US','0010Y654012P6PJQA0')
, ('2021-5-31','2022-5-14','0011v65402x8cjqAAA')
, ('2022-6-2','2022-1-13','0010Y654016OqkJQAS')
, ('2022-1-1','2022-11-11','0010Y654016OqIaQAK')
) a(Start_Date ,End_Date ,Customer_ID)
UNION ALL
select '2022-9-30' reporting_date, count(case when Start_Date>'2022-9-301' and End_Date<='2022-9-30' then Customer_ID end)
from (values ('2022-10-14','2022-8-19','0010Y654012P6KuQAK')
, ('2022-3-15','2022-9-14','0011v65402PoSpVAAV')
, ('2021-1-11','2022-10-11','0010Y654012P6DuQAK')
, ('2022-12-1','2022-5-14','0011v65402u7muLAAQ')
, ('2021-1-30','2022-3-14','0010Y654012P6DuQAK')
, ('2022-10-31','2022-2-14','0010Y654012P6PJQA0')
, ('2021-10-31','US','0010Y654012P6PJQA0')
, ('2021-5-31','2022-5-14','0011v65402x8cjqAAA')
, ('2022-6-2','2022-1-13','0010Y654016OqkJQAS')
, ('2022-1-1','2022-11-11','0010Y654016OqIaQAK')
) a(Start_Date ,End_Date ,Customer_ID)
It is possible to provide date ranges as a separate table/subquery, join to the actual data and perform grouping:
select s.start_d, s.end_d, COUNT(Customer_ID) AS total
FROM (SELECT '2022-10-31'::DATE, '2022-10-31'::DATE
UNION SELECT '2022-09-30', '2022-09-30')
AS s(start_d, end_d)
LEFT JOIN (values ('2022-10-14','2022-8-19','0010Y654012P6KuQAK')
, ('2022-3-15','2022-9-14','0011v65402PoSpVAAV')
, ('2021-1-11','2022-10-11','0010Y654012P6DuQAK')
, ('2022-12-1','2022-5-14','0011v65402u7muLAAQ')
, ('2021-1-30','2022-3-14','0010Y654012P6DuQAK')
, ('2022-10-31','2022-2-14','0010Y654012P6PJQA0')
, ('2021-10-31','2021-10-31','0010Y654012P6PJQA0')
, ('2021-5-31','2022-5-14','0011v65402x8cjqAAA')
, ('2022-6-2','2022-1-13','0010Y654016OqkJQAS')
, ('2022-1-1','2022-11-11','0010Y654016OqIaQAK')
) a(Start_Date ,End_Date ,Customer_ID)
ON a.Start_Date>s.start_d and a.End_Date<=s.end_d
GROUP BY s.start_d, s.end_d;
Output:

Calculate employee shift based on 1st login of the day

I want to calculate employees shift based on his system login time ,i am able to calculate shifts based on login times .now i want to calculate shift only for 1st login entry for given day if there are multiple logins for same day.Please help how i can do this .
**
SQL Query :
WITH shiftalloence AS
(
SELECT (timesheet.start_time_server) ,
users.first_name + ' ' + users.last_name AS employee_name ,
CASE
WHEN Dateadd(d, -Datediff(d, 0, dbo.[timesheet].start_time_server), dbo.[timesheet].start_time_server) BETWEEN '05:30:00' AND '08:00:00' THEN 'Morning'
WHEN Dateadd(d, -Datediff(d, 0, dbo.[timesheet].start_time_server), dbo.[timesheet].start_time_server) BETWEEN '08:01:00' AND '11:00:00' THEN 'General'
WHEN Dateadd(d, -Datediff(d, 0, dbo.[timesheet].start_time_server), dbo.[timesheet].start_time_server) BETWEEN '11:05:00' AND '18:00:00' THEN 'Evening'
ELSE '0'
END AS shift
FROM timesheet
JOIN users
ON timesheet.user_id=users.user_id
WHERE Month(start_time_server)=Month(Getdate())
AND Datename(weekday,timesheet.start_time_server) IN 'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday')
AND
start_time_server NOT IN
(
SELECT timesheet.start_time_server
FROM timesheet
JOIN leaves
ON timesheet.user_id=leaves.user_id
WHERE CONVERT(varchar(10),timesheet.start_time_server,111) =CONVERT(varchar(10),leaves.start_time_server,111)
AND task_type_name IN ('leave',
'Half Day') )), tt AS
(
SELECT shiftalloence.employee_name ,
count(
CASE
WHEN shift = 'Morning' THEN 1
ELSE NULL
END) AS 'Morning',
count(
CASE
WHEN shift = 'General' THEN 1
ELSE NULL
END) AS 'General' ,
count(
CASE
WHEN shift = 'Evening' THEN 1
ELSE NULL
END) AS 'Evening'
FROM shiftalloence
GROUP BY employee_name )SELECT *
FROM tt
**
Could you just simply distinct select and order by ASC or DESC depending on the dates? This would allow you to show just the shift/day/id you're wanting and showing you the first time they logged in because you're ordered it in the way you're wanting.
This works because if you get back 3 rows and order by the datetime asc/desc you can also simply do select top(1). It'll grab just the top record in that list for that shift/day/person.
Small example of what I am saying:
SELECT TOP 1 * FROM Employees
order by datetime asc;
Something like that.

How to calculate prior year sales data in SQL

I'm attempting to build a table summarizing sales data by week. In it, I'm trying to have one of the adjacent columns show the sales figures for the same fiscal week during the prior year (which due to my organizations fiscal calendar, had a 53rd week last year). I also have need to compare (Comp Units/Comp Sales) to a period 52 weeks ago which is an entirely different fiscal week (Think Week 9 of 2019 comparing to Week 10 2018).
I've tried using both unions and full outer joins, but given the way the way my data is, they're inefficient (Because this is weekly data, unions ended up being inefficient as I needed to leave the date information out of the initial query, then updating columns in my table to reflect the week the data is for. This is obviously rife with opportunity for error, but also time consuming to do 105 times), or just didn't work (attempting a full outer join was returning the wrong answers for all columns). I've also tried utilizing CTEs as well, and that's not working for me either. I'm currently trying a CASE Statement, but that's also returning a null value. I'm not quite sure where to go next
#STANDARDSQL
SELECT
DTL.SKU_NBR AS SKU_NBR
, SLS.STR_NBR AS STR_NBR
, CONCAT(TRIM(CAST(SKU_HIER.SKU_NBR AS STRING)), ' ', '-', ' ', TRIM(SKU_HIER.SKU_DESC)) AS SKU
, CONCAT(TRIM(CAST(SKU_HIER.EXT_SUB_CLASS_NBR AS STRING)), ' ', '-', ' ', TRIM(SKU_HIER.SUB_CLASS_DESC)) AS SUB_CLASS
, CONCAT(TRIM(CAST(SKU_HIER.EXT_SUB_SC_NBR AS STRING)), ' ', '-', ' ', TRIM(SKU_HIER.SUB_SC_DESC)) AS SUB_SUB_CLASS
, LOCATION.MKT_NM AS MARKET_NAME
, LOCATION.RGN_NM AS REGION_NAME
, LOCATION.DIV_NM AS DIVISION_NAME
, LOCATION.DIV_NBR AS DIVISION_NUMBER
, LOCATION.RGN_NBR AS REGION_NUMBER
, LOCATION.MKT_NBR AS MARKET_NUMBER
, COMP.STR_COMP_IND AS COMP_IND
, COMP.PY_STR_COMP_IND AS PRIOR_COMP_IND
, CALENDAR.FSCL_WK_DESC AS FISCAL_WEEK
, CALENDAR.FSCL_PRD_DESC AS FISCAL_PERIOD
, CALENDAR.FSCL_WK_END_DT AS END_DATE
, CALENDAR.FSCL_WK_BGN_DT AS BEGIN_DATE
, CALENDAR.FSCL_YR AS FISCAL_YEAR_NBR
, CALENDAR.FSCL_WK_NBR AS WEEK_NUMBER
, CALENDAR.FSCL_YR_WK_KEY_VAL AS FISCAL_KEY
, CALENDAR.LY_FYR_WK_KEY_VAL AS LY_FISCAL_KEY
, SUM(COALESCE(DTL.UNT_SLS,0)) AS UNITS
, SUM(COALESCE(DTL.EXT_RETL_AMT,0) + COALESCE(DTL.TOT_GDISC_DTL_AMT,0))
AS SALES
, SUM(CASE
WHEN 1=1 THEN (COALESCE(DTL.EXT_RETL_AMT,0) + COALESCE(DTL.TOT_GDISC_DTL_AMT,0)) * COMP.STR_COMP_IND
ELSE 0 END) AS COMP_SALES
, SUM(CASE
WHEN 1=1 THEN (COALESCE(DTL.UNT_SLS,0)) * COMP.STR_COMP_IND
ELSE 0 END) AS COMP_UNITS
, SUM(CASE
WHEN 1=1 AND SLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 364 DAY)
THEN (COALESCE(DTL.EXT_RETL_AMT,0) +
COALESCE(DTL.TOT_GDISC_DTL_AMT,0)) * COMP.PY_STR_COMP_IND
ELSE NULL END)
AS LY_COMP_SALES
, SUM(CASE
WHEN 1=1 AND SLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 364 DAY)
THEN (COALESCE(DTL.UNT_SLS,0)) * COMP.PY_STR_COMP_IND
ELSE NULL END)
AS LY_COMP_UNITS
, SUM(CASE
WHEN SLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 371 DAY)
THEN (COALESCE(DTL.EXT_RETL_AMT,0) +
COALESCE(DTL.TOT_GDISC_DTL_AMT,0))
ELSE NULL END)
AS LY_SALES
, SUM(CASE
WHEN SLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 371 DAY)
THEN (COALESCE(DTL.UNT_SLS,0))
ELSE NULL END)
AS LY_UNITS
FROM `pr-edw-views.SLS.POS_SLS_TRANS_DTL` AS SLS
INNER JOIN
UNNEST (SLS.DTL) AS DTL
JOIN `pr-edw-views.SHARED.MVNDR_HIER` AS MVNDR
ON DTL.DERIV_MVNDR.MVNDR_NBR = MVNDR.MVNDR_NBR
JOIN `pr-edw-views.SHARED.SKU_HIER_FD` AS SKU_HIER
ON SKU_HIER.SKU_NBR = DTL.SKU_NBR
AND SKU_HIER.SKU_CRT_DT = DTL.SKU_CRT_DT
JOIN `pr-edw-views.SHARED.LOC_HIER_FD` AS LOCATION
ON LOCATION.LOC_NBR = SLS.STR_NBR
JOIN `pr-edw-views.SHARED.CAL_PRD_HIER_FD` AS CALENDAR
ON CALENDAR.CAL_DT = SLS_DT
JOIN `pr-edw-views.SLS.STR_COMP_DAY` AS COMP
ON COMP.CAL_DT = CALENDAR.CAL_DT
AND COMP.STR_NBR = SLS.STR_NBR
WHERE CALENDAR.FSCL_WK_END_DT BETWEEN '2018-01-29' AND '2019-04-07'
AND SLS.SLS_DT BETWEEN '2018-01-29' AND '2019-04-07'
AND POS_TRANS_TYP_CD in ('S', 'R')
AND SKU_HIER.EXT_CLASS_NBR = '025-004'
AND MVNDR.MVNDR_NBR IN (74798, 60002238, 73059, 206820, 76009, 40263, 12879, 76722, 10830, 206823, 87752, 60052261, 70401, 51415, 51414)
AND SKU_HIER.LATEST_SKU_CRT_DT_FLG = TRUE
GROUP BY
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
I'm currently getting null values in my LY_SALES, LY_UNITS, LY_COMP_SALES and LY_COMP_UNITS columns, though I know there should have been locations with sales of those items from the same period the previous year. What I'm trying to get to is having those prior year values showing up along side the current year values. Any help would be hugely appreciated!
Thanks!
Such a condition can never be fulfilled : SLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 371 DAY). Simply because a SLS_DT is not equal to SLS_DT-371.
You can pre-aggregate the table in a CTE (adding SLS_DT to the group by columns) and then replace the CASE with a join to the pre-aggregated table. Aim at something like this: and it will become something like (notice - no SUM in the case):
CASE WHEN AGGSLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 371 DAY)
THEN (COALESCE(AGGSLS.SUM_EXT_RETL_AMT,0) +
COALESCE(AGGSLS.SUM_TOT_GDISC_DTL_AMT,0))
ELSE NULL END
Two things:
1) WHEN 1=1 can be expressed simply as WHEN TRUE, this way it is easier to move statements around without breaking the AND/OR chaining
2) to get the last year's sales. You can either omit the year from the final query and limit the output with a where clause or create a smaller table that has the sales this year, sales last year per week.
In my humble opinion sales last year for weeknum is the best option, as you can use it elsewhere. But it's pretty similar to what you wr
It would look something like:
SELECT CALENDAR.FSCL_WK_DESC as week_num,
sum(case when year = year(current_date()) then (COALESCE(DTL.UNT_SLS,0)) * COMP.STR_COMP_IND else 0 end) as this_year
sum(case when year = year(current_date())-1 then (COALESCE(DTL.UNT_SLS,0)) * COMP.STR_COMP_IND else 0 end) as last_year
And then you join back to the original table using week_num
Hope you find it useful
Cheers!

Invalid identifier in pivot table

Here is my query:
SELECT NVL(REVENUE,0), OUTNO, MONTH_NAME FROM
(
SELECT ROUND((RETURNDATE-STARTDATE)*DAILYRATE) AS REVENUE,
OUTNO,
EXTRACT(MONTH FROM RETURNDATE)AS MONTH_NAME
FROM RAGREEMENT LEFT JOIN VEHICLE ON
RAGREEMENT.LICENSENO=VEHICLE.LICENSENO
AND EXTRACT(YEAR FROM RETURNDATE)=EXTRACT(YEAR FROM SYSDATE)-1
)
PIVOT (
SUM(REVENUE)
FOR OUTNO IN (1,2,3,4,5,6,-1 AS TOTAL)
)
ORDER BY MONTH_NAME;
and here is the error
SELECT NVL(REVENUE,0), OUTNO, MONTH_NAME FROM
*
ERROR at line 1:
ORA-00904: "OUTNO": invalid identifier
I fail to understand why this happens when SELECT * works perfectly
What comes out from a pivot is a whole new set of columns names, and for each one of those new columns, you will need an NVL() or COALESCE(). This is because a completely new "matrix" is formed and many positions in this can be null. You cannot overcome this by using NVL() in the inner subquery.
Assuming you want months as columns your query might look more like this:
SELECT
OUTNO
, NVL('M1', 0)
, NVL('M2', 0)
, NVL('M3', 0)
, NVL('M4', 0)
, NVL('M5', 0)
, NVL('M6', 0)
, NVL('M7', 0)
, NVL('M8', 0)
, NVL('M9', 0)
, NVL('M10', 0)
, NVL('M11', 0)
, NVL('M12', 0)
FROM (
SELECT
ROUND((RETURNDATE - STARTDATE) * DAILYRATE) AS REVENUE
, OUTNO
, 'M' || EXTRACT(MONTH FROM RETURNDATE) AS MONTH_NAME
FROM RAGREEMENT
LEFT JOIN VEHICLE ON RAGREEMENT.LICENSENO = VEHICLE.LICENSENO
AND EXTRACT(YEAR FROM RETURNDATE) = EXTRACT(YEAR FROM SYSDATE) - 1
)
PIVOT(
SUM(REVENUE)
FOR MONTH_NAME IN ('M1','M2','M3','M4','M5','M6','M7','M8','M9','M10','M11','M12')
)
ORDER BY OUTNO;
This line produces the new columns:
FOR MONTH_NAME IN ('M1','M2','M3','M4','M5','M6','M7','M8','M9','M10','M11','M12')
and it is each one of these you will need to "fix" for nulls in the select clause.
To put OUTNO values into columns requires a similar pattern but you need to know what the distinct set of values will be from that originating column. This MIGHT be 1,2,3,4,5,6,-1 but I wasn't certain.
nb: I prefixed 'M' in columns headings as many systems object to numbers as heading names.

SQL Server 2008 multiple column filter

I have stuck on sql query to bring the wanted data. I have table as following
I have tried cte table but did not work . I need the get source 'O' if available else 'T' with max sequence as above result table.
select district
, id
, building
, year
, date
, period
, sequence
, source from GetAttData gt with (nolock) where sequence in (select max(sequence) from GetAttData with (nolock)
where district = gt.district
and building = gt.building
and year = gt.year
and id= gt.id
group by district, id, building, year, date, period)
and source = 'O'
select
district, id, building, year, date, period, sequence, source
from (
select district, id, building, year, date, period, sequence, source,
row_number() over(partition by district, id, building, year, date, period
order by case when source = 'O' then 0 else 1 end, sequence desc
) as takeme
) foo
where takeme = 1