How to choose table column dynamically? - vba

I have a data table in which I have month columns(fields).
How do I write a query that would select current month's column dynamically?
I tried doing this:
SELECT MonthName(month(date())) FROM my_table
That didn't work, so I tried several different ways that would return the month name for a query to use as field name, but so far nothing worked.
Can anybody point me to a solution?

You have a data source with a column for each month. You could use Switch() to retrieve the values from the column whose name matches the current month.
SELECT
Switch
(
Month(Date())= 1, [Jan],
Month(Date())= 2, [Feb],
Month(Date())= 3, [Mar],
Month(Date())= 4, [Apr],
Month(Date())= 5, [May],
Month(Date())= 6, [Jun],
Month(Date())= 7, [Jul],
Month(Date())= 8, [Aug],
Month(Date())= 9, [Sep],
Month(Date())=10, [Oct],
Month(Date())=11, [Nov],
Month(Date())=12, [Dec]
) AS current_month_column
FROM my_table;
However, I would try to transform the data source instead, converting columns to rows.
SELECT 'Jan' AS month_name, [Jan] As month_value FROM my_table
UNION ALL
SELECT 'Feb' AS month_name, [Feb] As month_value FROM my_table
UNION ALL
...
You could store the union result set in another table and query that, or query the union query.
SELECT month_name, month_value
FROM YourTable
WHERE month_name = MonthName(Month(Date()), True);

Dim db As Database
Dim strSQL As String
Set db = CurrentDb
strSQL = "SELECT " & left(MonthName(Month(Date)), 3) & " INTO new_table FROM my_table"
db.Execute strSQL

Related

Apply Mapping of Key-Value pair in Snowflake SQL

I have this Table:
Table_1:
KeyValue, Month
1, Oct,
3, Nov,
4, Sep,
5, Jan
upto "December". I want this tale to use as dictionary for another table query. So, if i am giving a Case query, where i am getting the Month of a date than this month should be replaced by the KeyValue of Table_1. For example:
CAST(Month(getdate()) as int)
gives "Sep" but the output should be
"4" because it is KeyValues of 'Sep' in Table_1
How it can be achieved in Snowflake?
It is just a subquery that perfrom lookup in dictionary table:
SELECT *, (SELECT t1.KeyValue FROM Table_1 AS t1 WHERE t1.Month = MONTH(GETDATE()))
FROM some_tab;
Also possible to implement as JOIN:
SELECT s.*, t1.KeyValue
FROM some_tab AS s
JOIN Table_1 AS t1
ON t1.Month = s.<col_name>;
I am trying to understand what is so complex here when you can achieve it with a simple join.
Consider month_mapping as your mapping table with key-value pair, and dataset as another table that you want to join with
with month_mapping (month_key, month_value) as
(
select * from
(
values (1, 'Oct')
, (3, 'Nov')
, (4, 'Sep')
, (5, 'Jan')
)
)
, dataset (actual_date) as
(
select * from
values (current_timestamp)
, (dateadd(month, 1, current_timestamp))
, (dateadd(month, 2, current_timestamp))
, (dateadd(month, 4, current_timestamp))
, (dateadd(day, 2, current_timestamp))
, (dateadd(day, -10, current_timestamp))
, (dateadd(day, 20, current_timestamp))
)
select ds.actual_date, mm.month_key, mm.month_value
from dataset ds
inner join month_mapping mm
on upper(mm.month_value) = upper(monthname(ds.actual_date))

Database query sql

Company would like to find out if there is any correlation between different months of a year
and demerit codes so you have been assigned to generate a report that shows for ALL the
demerits, the code, description, total number of offences committed for the demerit code
so far in any month (of any year) and then the total of offences committed for the demerit
code in each month (of any year). The column headings in your output should be renamed
as Demerit Code, Demerit Description, Total Offences (All Months), and then the first three
letters of each month (with the first letter in uppercase). The output must be sorted by
Total Offences (All Months) column in descending format and where there is more than
one demerit code with the same total, sort them by demerit code in ascending format. Your
output must have the form shown below. Your output can clearly be different from the
following output.
select d.dem_code as "Demerit Code", d.dem_description as "Demerit Description", count(o.off_no) as " Total Offences (All Months)",
select off_datetime from offence where to_char(off_datetime, 'Mon') == 'Jan'
from demerit d join offence o
on d.dem_code = o.dem_code
group by d.dem_code, dem_description
Can anyone tell me what's wrong with my query? what would be the solution for this, I've attached a copy of how output should be
(NOTE offence and demerit are different tables
y
select
[Demerit Code],[Demerit Description],[Total Offences (All Months)],
isnull(Jan,0) [Jan],isnull(Feb,0) [Feb],isnull(Mar,0) [Mar],isnull(Apr,0) [Apr],isnull(May,0) [May],
isnull(Jun,0) [Jun],isnull(Jul,0) [Jul],isnull(Aug,0) [Aug],isnull(Sep,0) [Sep],isnull(Oct,0) [Oct],
isnull(Nov,0) [Nov],isnull(Dec,0) [Dec]
from (
select d.dem_code as 'Demerit Code',
d.dem_description as 'Demerit Description',
o.off_no,
isnull(sum(o.off_no) OVER() ,0)'Total Offences (All Months)',
FORMAT(o.off_datetime, 'MMM', 'en-US') as 'DateExp'
from demerit d
inner join offence o
on d.dem_code = o.dem_code
group by d.dem_code,d.dem_description,FORMAT(o.off_datetime, 'MMM', 'en-US'),o.off_no
) as demerits
pivot (
sum(demerits.off_no)
FOR DateExp IN (
[Jan],
[Feb],
[Mar],
[Apr],
[May],
[Jun],
[Jul],
[Aug],
[Sep],
[Oct],
[Nov],
[Dec])
) as pivotdemerits

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!

sql- Show each month as field name for sum(qty) of items

I'd like to show each month's sum qty for the month correspondingly
ItemCode | October | November | December | January
PZ 0 0 12 36
So far my query looks like
And my SQL is
SELECT Detail.ItemCode
,SUM(Detail.QuantityOrdered) AS Total_Quantity
,MonthName(Month([Header.OrderDate])) AS ['Month Name']
FROM Detail
INNER JOIN Header ON Detail.SalesOrderNo = Header.SalesOrderNo
WHERE Header.OrderDate >= dateadd("m", - 4, DATE ())
GROUP BY Detail.ItemCode
,Header.OrderDate
ORDER BY SUM(Detail.QuantityOrdered) DESC;
And my Header.OrderDate looks like 12/25/2016.
Should I use crossover? I have looked up a lot but none seems applicable.. Thank you so much in advance!!
As #Jayvee mentioned, Transform looks promising.
Alternatively, you can do conditional aggregation, been a while since I worked with Access, but something like this:
SELECT Detail.ItemCode
, SUM(CASE WHEN Month([Header.OrderDate]) = 1 THEN Detail.QuantityOrdered END) AS 'January'
, SUM(CASE WHEN Month([Header.OrderDate]) = 2 THEN Detail.QuantityOrdered END) AS 'February'
, SUM(CASE WHEN Month([Header.OrderDate]) = 3 THEN Detail.QuantityOrdered END) AS 'March'
FROM Detail
INNER JOIN Header ON Detail.SalesOrderNo = Header.SalesOrderNo
WHERE Header.OrderDate >= dateadd("m", - 4, DATE ())
GROUP BY Detail.ItemCode
ORDER BY Detail.ItemCode;
Edit: Looks like Transform handles it dynamically already, something like this:
TRANSFORM SUM(Detail.QuantityOrdered)
SELECT Detail.ItemCode
FROM Detail
INNER JOIN Header ON Detail.SalesOrderNo = Header.SalesOrderNo
WHERE Header.OrderDate >= dateadd("m", - 4, DATE ())
GROUP BY Detail.ItemCode
PIVOT MonthName(Month([Header.OrderDate]))
Not sure if it will handle the function in the PIVOT you may need a subquery to get the monthname or other workaround.
Seems to me that what you are looking for is unpivot, but it does not exist in MS-Acess.
The simplest way to replicate would be something like this:
SELECT ItemCode, October as Total_Quantity, 'October' as MonthName
UNION
SELECT ItemCode, November as Total_Quantity, 'November' as MonthName
UNION
SELECT ItemCode, December as Total_Quantity, 'December'as MonthName
UNION
SELECT ItemCode, January as Total_Quantity, 'January' as MonthName

MySQL - Grouping dayname() for unique columns

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)