Related
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.
I have followed code which is supposed to give me consecutive records using PlanId and costcentreid. for example in the image the record number 7 has costcentreid of 14 and the costcentreid before that is 5, so then it will ignore all the records before that and return me StartDate of 2017-07-12. if the previous record was of the same cost centre, then it would keep going back till the cost centre is different and then return me the lowest date but it's not doing that. i have provided my sql. Could you please help?
Sample Data:
Scenario 1: Correct Answer should be '2017-07-12 11:56:52.560'
DECLARE #T TABLE (StartDate, PlanId, CostCentreId, PositionId, CostCentreFlavourID, CustomerPositionID)
INSERT #T(StartDate, PLanId, CostCentreID, PositionId, CostCentreFlavourID, CustomerPOsitionID)
VALUES('1998-10-23 00:00:00.000', 19130, 14, 129, 3, 1, 766 ),
('2010-06-22 00:00:00.000', 19130, 207, 25, 3, 1,16247),
('2012-05-01 16:27:04.460', 19130, 42, 14, 3, 1,23946),
('2013-04-30 18:57:57.617', 19130, 295, 14, 3, 1,29453),
('2015-03-03 09:31:28.133', 19130, 275, 5, 3,1, 39286),
('2015-06-26 15:48:35.637', 19130, 195, 5, 3,1,41985),
('2017-07-12 11:56:52.560', 19130, 1445, 14, 3, 1,57699)
Scenario 2: Correct Answer should be : '2015-06-26 15:48:35.637'
DECLARE #T TABLE (StartDate, PlanId, CostCentreId, PositionId, CostCentreFlavourID, CustomerPositionID)
INSERT #T(StartDate, PLanId, CostCentreID, PositionId, CostCentreFlavourID, CustomerPOsitionID)
VALUES('1998-10-23 00:00:00.000', 19130, 14, 129, 3,1,766 ),
('2010-06-22 00:00:00.000', 19130, 207, 25, 3, 1,16247),
('2012-05-01 16:27:04.460', 19130, 42, 14, 3, 1,23946),
('2013-04-30 18:57:57.617', 19130, 295, 14, 3, 1,29453),
('2015-03-03 09:31:28.133', 19130, 275, 5, 3, 1,39286),
('2015-06-26 15:48:35.637', 19130, 195, 14, 3,1, 41985),
('2017-07-12 11:56:52.560', 19130, 1445, 14, 3, 1,57699)
Scenario 3: Correct Answer should be: '2012-05-01 16:27:04.460'
DECLARE #T TABLE (StartDate, PlanId, CostCentreId, PositionId, CostCentreFlavourID, CustomerPositionID)
INSERT #T(StartDate, PLanId, CostCentreID, PositionId, CostCentreFlavourID, CustomerPOsitionID)
VALUES('1998-10-23 00:00:00.000', 19130, 14, 129, 3,1,766 ),
('2010-06-22 00:00:00.000', 19130, 207, 25, 3,1, 16247),
('2012-05-01 16:27:04.460', 19130, 42, 14, 3,1, 23946),
('2013-04-30 18:57:57.617', 19130, 295, 14, 3,1, 29453),
('2015-03-03 09:31:28.133', 19130, 275, 14, 3, 1,39286),
('2015-06-26 15:48:35.637', 19130, 195, 14, 3,1, 41985),
('2017-07-12 11:56:52.560', 19130, 1445, 14, 3,1, 57699)
WITH cte
AS (SELECT cp1.StartDate,
fp.PlanId,
p.CostCentreID,
p.PositionID,
fp.CostCentreFlavourId,
fp.CustomerWithNDISNumberOfPlans,
cp1.CustomerPositionID,
ROW_NUMBER() OVER (PARTITION BY cp1.CustomerID ORDER BY cp1.StartDate) AS CustomerRow,
ROW_NUMBER() OVER (PARTITION BY cp1.CustomerID, p.CostCentreID ORDER BY cp1.StartDate) AS CustomerCostCentreRow ,
ROW_NUMBER() OVER (PARTITION BY cp1.CustomerID ORDER BY cp1.StartDate)
- ROW_NUMBER() OVER (PARTITION BY cp1.CustomerID, p.CostCentreID ORDER BY cp1.StartDate) rn3
FROM #FlavouredPlans fp
INNER JOIN dbo.tblCustomerPositions cp1
ON cp1.CustomerID = fp.LADSCustomerID
INNER JOIN dbo.tblPositions p
ON p.PositionID = cp1.PositionID
--AND fp.CostCentreId = p.CostCentreID
WHERE fp.CostCentreFlavourId = 3
AND fp.OrderOfPlans = 1
),
ctePositionStartDate
AS (SELECT *,
MIN(cte.StartDate) OVER (PARTITION BY PlanId, CostCentreID, startdate, rn3) MinStartDate,
ROW_NUMBER() OVER (PARTITION BY PlanId ORDER BY cte.StartDate ASC) [Order]
FROM cte )
SELECT *
FROM ctePositionStartDate
WHERE ctePositionStartDate.planid = 19130
You can get your result by using window functions. Check this query
DECLARE #T TABLE (StartDate datetime, PlanId int, CostCentreId int, PositionId int, CostCentreFlavourID int, CustomerPositionID int)
INSERT #T(StartDate, PLanId, PositionId, CostCentreID, CostCentreFlavourID, CustomerPOsitionID)
VALUES
('19981023 00:00:00.000', 19130, 14, 129, 3,1),
('20100622 00:00:00.000', 19130, 207, 25, 3,1),
('20120501 16:27:04.460', 19130, 42, 14, 3,1),
('20130430 18:57:57.617', 19130, 295, 12, 3,1),
('20150303 09:31:28.133', 19130, 275, 14, 3, 1),
('20150626 15:48:35.637', 19130, 195, 14, 3,1),
('20170712 11:56:52.560', 19130, 1445, 14, 3,1)
select
*
from (
select
*, row_number() over (partition by PlanId, CostCentreID, rn1 - rn2 order by StartDate) r3
, max(StartDate) over (partition by PlanId, CostCentreID, rn1 - rn2) mx1
, max(StartDate) over (partition by PlanId) mx2
from (
select
*, row_number()over(partition by PlanId order by StartDate) rn1
, row_number()over(partition by PlanId, CostCentreID order by StartDate) rn2
from
#T
) t
) t
where
mx1 = mx2
and r3 = 1
I've got some periodic counter data (like once a second) from different objects that I wish to combine into an hourly total.
If I do it with separate column names, it's pretty straightforward:
CREATE TABLE ts1 (
id INTEGER,
ts TIMESTAMP,
count0 integer,
count1 integer,
count2 integer
);
INSERT INTO ts1 VALUES
(1, '2017-12-07 10:37:48', 10, 20, 50),
(2, '2017-12-07 10:37:48', 13, 7, 88),
(1, '2017-12-07 10:37:49', 12, 23, 34),
(2, '2017-12-07 10:37:49', 11, 13, 46),
(1, '2017-12-07 10:37:50', 8, 33, 80),
(2, '2017-12-07 10:37:50', 9, 3, 47),
(1, '2017-12-07 10:37:51', 17, 99, 7),
(2, '2017-12-07 10:37:51', 9, 23, 96);
SELECT id, date_trunc('hour', ts + '1 hour') nts,
sum(count0), sum(count1), sum(count2)
FROM ts1 GROUP BY id, nts;
id | nts | sum | sum | sum
----+---------------------+-----+-----+-----
1 | 2017-12-07 11:00:00 | 47 | 175 | 171
2 | 2017-12-07 11:00:00 | 42 | 46 | 277
(2 rows)
The problem is that different objects have different numbers of counts (though each particular object's rows -- ones sharing the same ID -- all have the same number of counts). Hence I want to use an array.
The corresponding table looks like this:
CREATE TABLE ts2 (
id INTEGER,
ts TIMESTAMP,
counts INTEGER[]
);
INSERT INTO ts2 VALUES
(1, '2017-12-07 10:37:48', ARRAY[10, 20, 50]),
(2, '2017-12-07 10:37:48', ARRAY[13, 7, 88]),
(1, '2017-12-07 10:37:49', ARRAY[12, 23, 34]),
(2, '2017-12-07 10:37:49', ARRAY[11, 13, 46]),
(1, '2017-12-07 10:37:50', ARRAY[8, 33, 80]),
(2, '2017-12-07 10:37:50', ARRAY[9, 3, 47]),
(1, '2017-12-07 10:37:51', ARRAY[17, 99, 7]),
(2, '2017-12-07 10:37:51', ARRAY[9, 23, 96]);
I have looked at this answer https://stackoverflow.com/a/24997565/1076479 and I get the general gist of it, but I cannot figure out how to get the correct rows summed together when I try to combine it with the grouping by id and timestamp.
For example, with this I get all the rows, not just the ones with matching id and timestamp:
SELECT id, date_trunc('hour', ts + '1 hour') nts, ARRAY(
SELECT sum(elem) FROM ts2 t, unnest(t.counts)
WITH ORDINALITY x(elem, rn) GROUP BY rn ORDER BY rn
) FROM ts2 GROUP BY id, nts;
id | nts | array
----+---------------------+--------------
1 | 2017-12-07 11:00:00 | {89,221,448}
2 | 2017-12-07 11:00:00 | {89,221,448}
(2 rows)
FWIW, I'm using postgresql 9.6
The problem with you original query is that you're summing all elements, because GROUP BY id, nts is executed in outer query. Combining a CTE with LATERAL JOIN would do the trick:
WITH tmp AS (
SELECT
id,
date_trunc('hour', ts + '1 hour') nts,
sum(elem) AS counts
FROM
ts2
LEFT JOIN LATERAL unnest(counts) WITH ORDINALITY x(elem, rn) ON TRUE
GROUP BY
id, nts, rn
)
SELECT id, nts, array_agg(counts) FROM tmp GROUP BY id, nts
I can easily get total sales in this month and previous month.
SELECT ‘This Mount’, SUM(Price) FROM Sales
WHERE EXTRACT(MONTH FROM OrderDate) = EXTRACT(MONTH FROM CURRENT_DATE)
AND EXTRACT(YEAR FROM OrderDate) = EXTRACT(YEAR FROM CURRENT_DATE)
Union All
SELECT ‘Previous Month’, SUM(Price) FROM Sales
WHERE EXTRACT(MONTH FROM OrderDate) = EXTRACT(MONTH FROM CURRENT_DATE)
AND EXTRACT(YEAR FROM OrderDate) = EXTRACT(YEAR FROM CURRENT_DATE)
I want to get the total sales in this quarter and previous quarter.
Getting quarter from a date is very easy with MS-SQL as follows:
SELECT DATEPART(QUARTER, #date)
How can I do this with Firebird?
Use DECODE function in conjunction with EXTRACT:
SELECT
DECODE(EXTRACT(MONTH FROM <date_field>),
1, 'I',
2, 'I',
3, 'I',
4, 'II',
5, 'II',
6, 'II',
7, 'III',
8, 'III',
9, 'III',
'IV')
FROM
<some_table>
Or just
SELECT
(EXTRACT(MONTH FROM <date_field>) - 1) / 3 + 1
FROM
<some_table>
SELECT dates,
EXTRACT(MONTH from dates) as SalesMonth,
floor(((EXTRACT(MONTH from dates)-1) / 3.0 + 1)) as QTR
from CustomerPO
where ((dates > '1/1/2016') and (dates < '12/31/2016'))
order by dates
Here, 'dates' is the field name of Order table 'CustomerPO'
SELECT dates,
EXTRACT(MONTH from dates) as SalesMonth,
ceil(EXTRACT(MONTH from dates) / 3) as QTR
from CustomerPO
where ((dates > '1/1/2016') and (dates < '12/31/2016'))
order by dates
I asked a question for a complex query yesterday, and I was offered an example. I really would like to get it to work but there was a syntax error in it that I can't figure out. Keep in mind that I was just introduced to CTE's earlier this week so hopefully this is an easy one.
I don't think I need to post the full code on here, so I'll just summarize
with cte as (select dateadd(hour, 1, cast(cast(getdate() -1 as date) as datetime)) as midnnight),
allhours as (
select 0 as hour, midnight as timestart, dateadd(hour, 1, timestart) as timeend from cte union all
select 1 as hour, dateadd(hour, 1, midnight), dateadd(hour, 2, midnight) from cte union all
....
select 23 as hour, dateadd(hour, 23, midnight), dateadd(hour, 24, midnight) from cte union all
)
select ah.hour,...
The (...) denotes unnecessary code that I omitted to make it less messy
But I am getting a syntax error on the parenthesis between select 23 and select ah.hour
"Incorrect syntax near ')'. Expecting SELECT, or '('.
Any help is greatly appreciated.
-J
You had a few syntax errors including a UNION ALL that was not needed at the bottom, and your first SELECT in the allhours was referencing an alias, so try this:
;with cte as
(
select dateadd(hour, 1, cast(cast(getdate() -1 as date) as datetime)) as midnight
),
allhours as
(
select 0 as hour, midnight as timestart, dateadd(hour, 1, midnight) as timeend
from cte
union all
select 1 as hour, dateadd(hour, 1, midnight), dateadd(hour, 2, midnight)
from cte
union all
select 23 as hour, dateadd(hour, 23, midnight), dateadd(hour, 24, midnight)
from cte
)
select *
from allhours
see SQL Fiddle with Demo
You should get rid of the last Union all here
hour, dateadd(hour, 23, midnight), dateadd(hour, 24, midnight) from cte union all
)
select ah.hour,...
Also, spell midnight right in the first line