Oracle Apex Bar Chart with Days of Week Aggregate - charts

I'm trying to create a bar chart (with Oracle Apex v21.1.0) showing employee absences broken down by days of the week. i.e. a count of absences for each day of the week.
I'm having problems getting the 7 bars for the days of the week to show in chronological order.
This is my SQL:
-- sql for chart showing count of days absent for each day of week
select
TO_CHAR(ABD_DATE, 'D') as Day_Index_DOW,
TO_CHAR(ABD_DATE, 'DY') as Day_Name_DOW,
COUNT(TO_CHAR(ABD_DATE, 'D')) as Count_DOW
from F_ABSENT_DAYS
where ABD_EMP_ID = :P410_EMP_ID
group by TO_CHAR(ABD_DATE, 'D'), TO_CHAR(ABD_DATE, 'DY')
order by TO_CHAR(ABD_DATE, 'D')
Chart settings are:
Series Name is set to Day_Index_DOW
Label is set to Day_Name_DOW
Value is set to Count_DOW
This produces the 7 bars with the correct counts for the days of week.
The problem is, they are sorted in alphabetical order (FRI, MON, SAT...).
I'm trying to get them in chronological order (MON, TUE, WED...).
Is the error in the SQL or a setting in the designer?

I created sample data to demo your example.
SQL Query:
select day_number, day_name, sum(count_dow)
from (
select TO_CHAR(sysdate, 'D') day_number, TO_CHAR(sysdate, 'DY') day_name, 5 count_dow
from dual
union
select TO_CHAR(sysdate+1, 'D') day_number, TO_CHAR(sysdate+1, 'DY') day_name, 4 count_dow
from dual
union
select TO_CHAR(sysdate+2, 'D') day_number, TO_CHAR(sysdate+2, 'DY')day_name, 3 count_dow
from dual
union
select TO_CHAR(sysdate+3, 'D') day_number, TO_CHAR(sysdate+3, 'DY')day_name, 2 count_dow
from dual
union
select TO_CHAR(sysdate+4, 'D') day_number, TO_CHAR(sysdate+4, 'DY')day_name, 1 count_dow
from dual
union
select TO_CHAR(sysdate+5, 'D') day_number, TO_CHAR(sysdate+5, 'DY')day_name, 4 count_dow
from dual
union
select TO_CHAR(sysdate+6, 'D') day_number, TO_CHAR(sysdate+6, 'DY')day_name, 8 count_dow
from dual
union
select TO_CHAR(sysdate+3, 'D') day_number, TO_CHAR(sysdate+3, 'DY')day_name, 2 count_dow
from dual
union
select TO_CHAR(sysdate+4, 'D') day_number, TO_CHAR(sysdate+4, 'DY')day_name, 1 count_dow
from dual
union
select TO_CHAR(sysdate+5, 'D') day_number, TO_CHAR(sysdate+5, 'DY')day_name, 4 count_dow
from dual
union
select TO_CHAR(sysdate+6, 'D') day_number, TO_CHAR(sysdate+6, 'DY')day_name, 8 count_dow
from dual
)
group by day_number, day_name
order by day_number;
I set the label and value properties:
This is the resulting chart:
According to NLS_TERRITORY parameter for my DB, the first day of the week is Sunday, can vary on yours.

Related

Oracle SQL return value from child table with minimum row number with values in specific list

I have a need to select all rows from a table (main table) and join to another table (child table). In the results set, I want to include one column from the child table, that is only the first row / line number with a column value in a specified list. If there is no match for the specified list, it should be (null)
Desired Result:
ORDER_NO
ORDER_DATE
ORDER CUST
ORDER_VALUE
ITEM
1
02/14/2022
12345
$1,000.00
APPLES
2
02/13/2022
67890
$5,000.00
(null)
3
02/12/2022
45678
$100.00
PEARS
Example:
Main Table: Order Table
Order Number (Handle)
Order Date,
Order Customer,
Order Value
ORDER_NO
ORDER_DATE
ORDER CUST
ORDER_VALUE
1
02/14/2022
12345
$1,000.00
2
02/13/2022
67890
$5,000.00
3
02/12/2022
45678
$100.00
Child Table: Order Details Tbl
Order Number (Handle)
Line Number = Order Line No
Ordered Item,
Ordered Qty
ORDER_NO
LINE_NO
ITEM
1
10
APPLES
1
20
ORANGES
1
30
LETTUCE
2
10
BROCCOLI
2
20
CAULIFLOWER
2
30
LETTUCE
3
10
KALE
3
20
RADISHES
3
30
PEARS
In this example, the returned column is essentially the first line of the order that is a fruit, not a vegetable. And if the order includes no matching fruit, null is returned.
What my code is thus far:
SELECT
MAIN.ORDER_NO,
MAIN.ORDER_DATE,
MAIN.ORDER_CUST,
MAIN.ORDER_VALUE,
B.ITEM
FROM
MAIN
LEFT JOIN
(
SELECT
CHILD.ORDER_NO,
CHILD.LINE_NO,
CHILD.ITEM
FROM
CHILD
WHERE
CHILD.ORDER_NO||'_'||LINE_NO IN
(
SELECT
CHILD.ORDER_NO||'_'||MIN(LINE_NO) AS ORDER_LINE_NO
FROM
CHILD
WHERE
CHILD.ITEM IN ('APPLES','ORANGES','PEACHES','PEARS','GRAPES')
GROUP BY
CHILD.ORDER_NO
)
) B ON MAIN.ORDER_NO = B.ORDER_NO
'''
This code is of course not working as desired, as table 'B' is including all results from CHILD.
From Oracle 12, you can use:
SELECT o.*,
d.item
FROM orders o
LEFT OUTER JOIN LATERAL(
SELECT *
FROM order_details d
WHERE o.order_no = d.order_no
AND item IN ('APPLES','ORANGES','PEACHES','PEARS','GRAPES')
ORDER BY line_no ASC
FETCH FIRST ROW ONLY
) d
ON (1 = 1)
In earlier versions you can use:
SELECT o.*,
d.item
FROM orders o
LEFT OUTER JOIN(
SELECT d.*,
ROW_NUMBER() OVER (PARTITION BY order_no ORDER BY line_no ASC)
AS rn
FROM order_details d
WHERE item IN ('APPLES','ORANGES','PEACHES','PEARS','GRAPES')
) d
ON (o.order_no = d.order_no AND rn = 1)
Which, for the sample data:
CREATE TABLE orders (ORDER_NO, ORDER_DATE, ORDER_CUST, ORDER_VALUE) AS
SELECT 1, DATE '2022-02-14', 12345, 1000.00 FROM DUAL UNION ALL
SELECT 2, DATE '2022-02-13', 67890, 5000.00 FROM DUAL UNION ALL
SELECT 3, DATE '2022-02-12', 45678, 100.00 FROM DUAL;
CREATE TABLE Order_Details (ORDER_NO, LINE_NO, ITEM) AS
SELECT 1, 10, 'APPLES' FROM DUAL UNION ALL
SELECT 1, 20, 'ORANGES' FROM DUAL UNION ALL
SELECT 1, 30, 'LETTUCE' FROM DUAL UNION ALL
SELECT 2, 10, 'BROCCOLI' FROM DUAL UNION ALL
SELECT 2, 20, 'CAULIFLOWER' FROM DUAL UNION ALL
SELECT 2, 30, 'LETTUCE' FROM DUAL UNION ALL
SELECT 3, 10, 'KALE' FROM DUAL UNION ALL
SELECT 3, 20, 'RADISHES' FROM DUAL UNION ALL
SELECT 3, 30, 'PEARS' FROM DUAL;
Both output:
ORDER_NO
ORDER_DATE
ORDER_CUST
ORDER_VALUE
ITEM
1
2022-02-14 00:00:00
12345
1000
APPLES
2
2022-02-13 00:00:00
67890
5000
null
3
2022-02-12 00:00:00
45678
100
PEARS
db<>fiddle here

SQL Group by Month

I have a table of Sales data with each line as a sale date mm/dd/yy.
I'm trying to create a query so I can see total sales for each month I have.
Would I have to create a column separate that dictates only the month? Or is there a way that it can take the month from that date format?
The short answer is: You don't need a separate column. You can group by the result of a function call.
The details of what that function might depend on your database, how you want results formatted, and performance considerations.
The following both work in Oracle:
SELECT extract(YEAR FROM ae.saledate), extract(MONTH FROM ae.saledate), count(*)
FROM mytable ae
GROUP BY extract(YEAR FROM ae.saledate), extract(MONTH FROM ae.saledate);
SELECT TO_CHAR(ae.saledate, 'YYYY-MM'), count(*)
FROM mytable ae
GROUP BY TO_CHAR(ae.saledate, 'YYYY-MM');
Edited to add versions that ignore year and only look at month (since I was making an assumption above that wasn't actually in the question):
SELECT extract(MONTH FROM ae.saledate), count(*)
FROM mytable ae
GROUP BY extract(MONTH FROM ae.saledate);
SELECT TO_CHAR(ae.saledate, 'MM'), count(*)
FROM mytable ae
GROUP BY TO_CHAR(ae.saledate, 'MM');
The following Query will helpful.
CREATE TABLE #TEMP
(SalesDate DATETime,
Amount float
)
INSERT INTO #TEMP
SELECT '2016-01-12', 12
UNION
SELECT '2016-01-13', 12
UNION
SELECT '2016-02-12', 12
UNION
SELECT '2016-03-12', 12
SELECT CONVERT(VARCHAR(7), SalesDate, 120) AS 'YYYY-MM',
SUM(Amount) as 'Amount'
FROM #Temp
GROUP BY CONVERT(VARCHAR(7), SalesDate, 120)
OUTPUT :
YYYY-MM Amount
------- ----------------------
2016-01 24
2016-02 12
2016-03 12
(3 row(s) affected)
For only Month Wise
SELECT RIGHT(CONVERT(VARCHAR(7), SalesDate, 120), 2) AS 'MM',
sum(Amount) as 'Amount'
from #Temp
group by RIGHT(CONVERT(VARCHAR(7), SalesDate, 120), 2)
Output:
MM Amount
---- ----------------------
01 24
02 12
03 12
(3 row(s) affected)

postgresql: Group select by year and month from epoch time

I need to get an output from the postgresql db as follows:
2016
Nov
Dec
2017
Jan
Feb
Mar
I've been googling, testing, playing but hasn't come close.
So I tuen to you guys that will show me what nord I am!
I do know how to do this in mysql but postgres no.
Oh yeah it is Postgres 9.6.
Not sure, but may be you need this ?
with your_table(dt) as(
select '2016-11-01'::date union all
select '2016-11-02'::date union all
select '2016-12-01'::date union all
select '2017-01-01'::date union all
select '2017-02-01'::date union all
select '2017-02-02'::date union all
select '2017-03-01'::date union all
select '2017-10-01'::date union all
select '2017-11-01'::date union all
select '2018-02-01'::date
)
-- Above is just table simulation, actual query is below:
select case when month_name is null then y::text else month_name end from (
select extract(year from dt) as y, 0 as month_number, null as month_name from your_table group by extract(year from dt)
union all
select extract(year from dt), extract(month from dt) as month_number, '--'||to_char(min(dt), 'Mon') as month_name from your_table
group by extract(year from dt), extract(month from dt)
) t
order by y, month_number

Getting the start date and end date of all weeks by giving the year

I have a query which displays a set of 52 numbers along with the respective dates of that week
SELECT kkk, TO_CHAR (start_date, 'DD-MON-YYYY'),
TO_CHAR (start_date + 6, 'DD-MON-YYYY') AS end_day
FROM (SELECT TRUNC (TRUNC (TO_DATE ('2014', 'YYYY'), 'YYYY') + 1 * 7,
'IW'
)
- 1 start_date,
ROWNUM AS kkk
FROM DUAL
CONNECT BY ROWNUM <= 52);
but the problem with this query is that I am only getting the first week dates but not for the next consecutive weeks.Please help
Try like this,
SELECT kkk,
TO_CHAR(start_date, 'DD-MON-YYYY') start_date,
TO_CHAR(start_date + 6, 'DD-MON-YYYY') end_day
FROM(
SELECT TRUNC(Trunc(to_date('2014', 'YYYY'),'YYYY')+ LEVEL * 7,'IW')-1 start_date ,
ROWNUM kkk
FROM duaL
CONNECT BY LEVEL <= 52
);
Instead of ROWNUM you can also use LEVEL, Like,
SELECT TRUNC(Trunc(to_date('2014', 'YYYY'),'YYYY')+ LEVEL * 7,'IW')-1 start_date ,
level kkk
FROM duaL
CONNECT BY LEVEL <= 52

deriving calendar month from week number

I've had a hunt around for something similar to this but can't find anything.
I have a query that provides the number of transactions that have occurred each day and need to group by year, month, week BUT of course some months span multiple week numbers, eg. Sept. & Oct. 2009.
Take for example week 39 last year (September & October). Thursday is the 1st October therefore 4 days of that week fall in Oct., therefore the volume of transactions for the last 3 days of Sept. should be added to the first week of October's totals? Clear?
For example:
VOLUME----TRANSACTION----YEAR----MONTH----WEEK
1264.1730----53----2009----September----37
2739.7200---109----2009----September----38
522.5500-----21----2009----October----39
1196.6450----51----2009----September----39
2827.9550---113----2009----October----40
2730.4050---110----2009----October----41
3763.7200---154----2009----October----42
3425.6250---137----2009----October----43
3551.8100---143----2009----November--44
2788.0150---113----2009----November--45
The problem is that the calendar is awkward, and there's not much you can do about it. As far as I can see, you have three choices:
Group by year and month. Display the week or weeks in the result but don't group by them.
Group by year and weeks. Display the month or months in the result but don't group by them.
Group by year, month, week, and accept that some of the groups contain less than one week's data. (i.e. what you have now)
From your description it seems like you want option 2:
SELECT year, MIN(month), week, SUM(transaction)
FROM Table1
GROUP BY year, week
Something like this would do:
-- For weeks starting Sunday and ending Saturday, the US default:
SET DATEFIRST 7
-- Alternatively, for weeks starting Saturday and ending Friday:
--SET DATEFIRST 6
SELECT
[Date]
, DATENAME(WEEKDAY,[Date]) AS [DayOfWeek]
, DATEADD(DAY,1-DATEPART(WEEKDAY,[Date]),[Date]) AS WeekStarting
, DATEADD(DAY,7-DATEPART(WEEKDAY,[Date]),[Date]) AS WeekEnding
FROM (
SELECT CONVERT(DATETIME,'20100124') UNION ALL
SELECT CONVERT(DATETIME,'20100125') UNION ALL
SELECT CONVERT(DATETIME,'20100126') UNION ALL
SELECT CONVERT(DATETIME,'20100127') UNION ALL
SELECT CONVERT(DATETIME,'20100128') UNION ALL
SELECT CONVERT(DATETIME,'20100129') UNION ALL
SELECT CONVERT(DATETIME,'20100130') UNION ALL
SELECT CONVERT(DATETIME,'20100131') UNION ALL
SELECT CONVERT(DATETIME,'20100201') UNION ALL
SELECT CONVERT(DATETIME,'20100202') UNION ALL
SELECT CONVERT(DATETIME,'20100203') UNION ALL
SELECT CONVERT(DATETIME,'20100204') UNION ALL
SELECT CONVERT(DATETIME,'20100205') UNION ALL
SELECT CONVERT(DATETIME,'20100206')
) a ([Date])
Then, convert your week start or end date to a month:
SELECT *
, WeekStartingMonthStart = DATEADD(DAY,1-DAY(WeekStarting),WeekStarting)
, WeekStartingMonthEnd = DATEADD(DAY,-1,DATEADD(MONTH,1,DATEADD(DAY,1-DAY(WeekStarting),WeekStarting)))
, WeekEndingMonthStart = DATEADD(DAY,1-DAY(WeekEnding),WeekEnding)
, WeekEndingMonthEnd = DATEADD(DAY,-1,DATEADD(MONTH,1,DATEADD(DAY,1-DAY(WeekEnding),WeekEnding)))
FROM (
SELECT
[Date]
, DATENAME(WEEKDAY,[Date]) AS [DayOfWeek]
, DATEADD(DAY,1-DATEPART(WEEKDAY,[Date]),[Date]) AS WeekStarting
, DATEADD(DAY,7-DATEPART(WEEKDAY,[Date]),[Date]) AS WeekEnding
FROM (
SELECT CONVERT(DATETIME,'20100124') UNION ALL
SELECT CONVERT(DATETIME,'20100125') UNION ALL
SELECT CONVERT(DATETIME,'20100126') UNION ALL
SELECT CONVERT(DATETIME,'20100127') UNION ALL
SELECT CONVERT(DATETIME,'20100128') UNION ALL
SELECT CONVERT(DATETIME,'20100129') UNION ALL
SELECT CONVERT(DATETIME,'20100130') UNION ALL
SELECT CONVERT(DATETIME,'20100131') UNION ALL
SELECT CONVERT(DATETIME,'20100201') UNION ALL
SELECT CONVERT(DATETIME,'20100202') UNION ALL
SELECT CONVERT(DATETIME,'20100203') UNION ALL
SELECT CONVERT(DATETIME,'20100204') UNION ALL
SELECT CONVERT(DATETIME,'20100205') UNION ALL
SELECT CONVERT(DATETIME,'20100206')
) a ([Date])
) a