I am having issues with a query that, if ran with hard-coded dates, will insert the correct number of rows into a table (170K+). The issue is, when I try to automate it, by replacing the hard-coded dates with date functions, the query will then only insert a single row into a newly truncated table.
Example hard-coded date: '20150401'
Sample of that same date, using the date function:
TO_CHAR(last_day(add_months(now(), -3))+1, 'YYYYMMDD')
The above TO_CHAR function returns the desired result, when ran separately.
Here is a cleaned-up version of the query that results in a single row being inserted:
INSERT INTO SCHEMA.INSERT_TABLE(
SELECT TO_CHAR(now(), 'YYYYMM') TRAN_MONTH,
SUM(CASE WHEN B.DATE = TO_CHAR(last_day(add_months(now(), -3))+1, 'YYYYMMDD')
THEN 'Do stuff'
END) AS Stuff1,
SUM(CASE WHEN B.DATE = TO_CHAR(last_day(add_months(now(), -3))+1, 'YYYYMMDD')
THEN 'Do other stuff'
END) AS Stuff2,
SUM(CASE WHEN B.DATE = TO_CHAR(last_day(add_months(now(), -3))+1, 'YYYYMMDD')
THEN 'Do really weird stuff'
END) AS Stuff3,
SUM(CASE WHEN B.DATE = TO_CHAR(last_day(add_months(now(), -3))+1, 'YYYYMMDD')
THEN 'Do really really weird stuff'
END) AS Stuff4,
SUM(CASE WHEN A.CODE= 1
THEN 'Do ... '
END) AS Stuff5,
FROM
(SELECT Col1, Col2... FROM Table_A) A,
(SELECT Col1, Col2... FROM Table_B) B,
(SELECT Col1, Col2... FROM Table_C) C,
(SELECT Col1, Col2... FROM Table_D) D,
(SELECT Col1, Col2... FROM Table_E) E,
WHERE 'Conditions for A, B, C, D, and E are met'
AND B.DATE = TO_CHAR(last_day(add_months(now(), -3))+1,'YYYYMMDD')
GROUP BY All of the things
ORDER BY Something
);
I have done quite a bit of testing, and research, but I haven't found a possible cause as to why the amount of records returned would be so drastically different.
Thank you,
Justin
I think it's because you added a 1 to the character string resulting from your last_day function. Check your parentheses:
WHERE 'Conditions for A, B, C, D, and E are met'
AND B.DATE = TO_CHAR(last_day(add_months(now(), -3)+1)
If it isn't that (or you really do want to add 1 to a character string), then I'm going to go out on a limb and assume that B.DATE is a column of type date. If so, the reason it isn't comparing correctly is because you're relying on implicit conversion. Change your date filter to explicitly convert both sides.
WHERE 'Conditions for A, B, C, D, and E are met'
AND B.DATE::date = (last_day(add_months(now(), -3)+1)::date
Related
I have this audit table
User
date
text
text 2
u1
2023-01-01
hi
yes
u1
2022-12-20
hi
no
u1
2022-12-01
hello
maybe
And I need as a result, something like this:
User
date
text
text 2
u1
2023-01-01
null
x
u1
2022-12-20
x
x
u1
2022-12-01
null
null
So I can know which column changed from the last time.
Something like this is working, but I think may be a way to optimize it? or at least generate a "more easy to look" query? (i need the information for almost 20 columns, not only 3)
SELECT
ta.audit_date,
ta.audit_user,
CASE
WHEN ta.audit_operation = 'I' THEN 'Insert'
WHEN ta.audit_operation = 'U' THEN 'Update'
END AS action,
CASE WHEN ta.column1 <> (SELECT column1
FROM audit_table ta1
WHERE ta1.id = 9207 AND ta1.audit_date < ta.audit_date
ORDER BY ta1.audit_date DESC
LIMIT 1)
THEN 'X' ELSE null END column1,
CASE WHEN ta.column2 <> (SELECT column2
FROM audit_table ta1
WHERE ta1.id = 9207 AND ta1.audit_date < ta.audit_date
ORDER BY ta1.audit_date DESC
LIMIT 1)
THEN 'X' ELSE null END column2,
CASE WHEN ta.column3 <> (SELECT column3
FROM audit_table ta1
WHERE ta1.id = 9207 AND ta1.audit_date < ta.audit_date
ORDER BY ta1.audit_date DESC
LIMIT 1)
THEN 'X' ELSE null END column3
FROM
audit_table ta
WHERE
ta.id = 9207
ORDER BY
audit_date DESC
Thank you!
I think you can just use the LAG() analytic function here. If I understand correctly:
SELECT *, CASE WHEN text != LAG(text) OVER (ORDER BY date) THEN 'x' END AS text_label,
CASE WHEN text2 != LAG(text) OVER (ORDER BY date) THEN 'x' END AS text2_label
FROM yourTable
ORDER BY date;
I did some digging within stackoverflow for a solution and nothing quite matched what I was after (I don't think).
My goal is to combine two queries that will return 3 columns [date, OUT, IN] as output.
On their own, the two queries return the correct output.
1st SELECT query for OUT returns
[03/01, 4],[03/02, 10],[03/03, 21],[03/01, 4]
2nd SELECT query for IN returns
[03/01, 4],[03/03, 25]
Using WITH to combine the two queries, two different ways, the outputs are identical.
[03/01, 4, 4], [03/03, 21, 25] -> OUT as inner query
[03/01, 4, 4], [03/03, 21, 25] -> IN as inner query
As can be seen, because nothing came IN on the 2nd and 4th of March, an empty row is returned for those dates. I believe the correct way to use the WITH query is to have the OUT as the inner query so the 2nd and 4th are part of the recursion in the outer query.
Pasted below is a simplified version of what the WITH query looks like. On its own, the inner query returns a count for each day of March. For some reason, the outer query does not return 0 when it does not have a count for the date in question (2nd and 4th).
Anyone have advice on how to solve this one? Could I be using COALESCE incorrectly?
WITH first_query (the_date, out) AS
(
SELECT DISTINCT ON(to_char(t1.date, 'dd')) to_char(t1.out_date, 'dd') AS out_date2, count(to_char(t1.out_date, 'dd')) AS out
FROM table_out AS t1
WHERE to_char(t1.out_date,'yyyy') = to_char(date_trunc('year', CURRENT_DATE), 'YYYY')
AND to_char(t1.out_date,'MM') = to_char(date_trunc('month', CURRENT_DATE), 'MM')
AND t1.out_id = 14
GROUP BY out_date2
)
SELECT fq.the_date AS day_of_month, fq.out, COALESCE( ( SELECT COUNT(to_char(t1.in_date, 'DD')) ), 0) AS in
FROM first_query fq, table_in t1
WHERE to_char(t1.in_date,'yyyy') = to_char(date_trunc('year', CURRENT_DATE), 'YYYY')
AND to_char(t1.in_date,'MM') = to_char(date_trunc('month', CURRENT_DATE), 'MM')
AND to_char(t1.in_date,'dd') = fq.the_date
GROUP BY day_of_month, fq.out
ORDER BY day_of_month ASC
The answer ended up requiring CAST and LEFT JOIN as Jeremy suggested. The timestamps made this harder than it had to be.
SELECT CAST(t1.out_date AS Date) AS date2, count(DISTINCT
t1.id) out, count(DISTINCT t2.id) AS in
FROM table_out as t1
LEFT JOIN table_in AS t2 ON CAST(t1.out_date AS Date) =
CAST(t2.in_date AS Date)
WHERE to_char(t1.out_date,'yyyy') =
to_char(date_trunc('year', CURRENT_DATE), 'YYYY')
AND to_char(t1.out_date,'MM') = to_char(date_trunc('month',
CURRENT_DATE), 'MM')
AND t1.out_id = 14
GROUP BY out_date2
The answer ended up requiring CAST and LEFT JOIN as Jeremy suggested. The timestamps made this harder than it had to be.
SELECT CAST(t1.out_date AS Date) AS date2, count(DISTINCT
t1.id) out, count(DISTINCT t2.id) AS in
FROM table_out as t1
LEFT JOIN table_in AS t2 ON CAST(t1.out_date AS Date) =
CAST(t2.in_date AS Date)
WHERE to_char(t1.out_date,'yyyy') =
to_char(date_trunc('year', CURRENT_DATE), 'YYYY')
AND to_char(t1.out_date,'MM') = to_char(date_trunc('month',
CURRENT_DATE), 'MM')
AND t1.out_id = 14
GROUP BY out_date2
I have a dataset where an id moves through stages A to D sequentially (A to B, B to C & C to D).
I a have timestamps that track when an id entered a particular stage.Here is what my data looks like
So I am interested in creating a field called 'Status' that shows the number of B, C, D converted based on the timestamp of A
For instance;
In the month of Aug'19 The number of 'A's=7
The number of 'B' converted when the timestamp of A is Aug'19 (irrespective of the date under Date_B)=5
The number of 'C' converted when the timestamp of A is Aug'19(irrespective of the date under Date_C)=5
The number of 'D' converted when the timestamp of A is Aug'19(irrespective of the date under Date_D)=5
I tried using union all, but its gives me the 'Status' in real time meaning 'date_B' under id 1 gets a date of Sept'19 not Aug'19.This is the query I used;
SELECT id,
CAST (Date_A AS DATE) AS 'Pivot Date',
'A' AS 'Status'
FROM table1
UNION ALL
SELECT id,
CAST (Date_B AS DATE) AS 'Pivot Date',
'B' AS 'Status'
FROM table1
UNION ALL
SELECT id,
CAST (Date_C AS DATE) AS 'Pivot Date',
'C' AS 'Status'
FROM table1
UNION ALL
SELECT id,
CAST (Date_D AS DATE) AS 'Pivot Date',
'D' AS 'Status'
FROM table1
Can someone point me in the right direction?
Thanks!
I am not totally sure if this is what you want, but try this:
SELECT
*, -- or only id or whatever
COUNT(date_a) OVER (PARTITION BY date_trunc('month', date_a)) AS a_of_the_month,
COUNT(date_b) OVER (PARTITION BY date_trunc('month', date_a)) AS already_converted_to_b,
COUNT(date_c) OVER (PARTITION BY date_trunc('month', date_a)) AS already_converted_to_c,
COUNT(date_d) OVER (PARTITION BY date_trunc('month', date_a)) AS already_converted_to_d
FROM table1;
Perhaps you only wanted the months and your numbers:
SELECT
date_trunc('month', date_a),
COUNT(date_a) AS a_of_the_month,
COUNT(date_b) AS already_converted_to_b,
COUNT(date_c) AS already_converted_to_c,
COUNT(date_d) AS already_converted_to_d
FROM table1
GROUP BY date_trunc('month', date_a);
In both cases you might also replace COUNT(date_a) by COUNT(*) if date_a has to be set always.
SELECT
CAST(c.DT AS DATE) AS 'Date'
, COUNT(p.PatternID) AS 'Count'
FROM CalendarMain c
LEFT OUTER JOIN Pattern p
ON c.DT = p.PatternDate
INNER JOIN Result r
ON p.PatternID = r.PatternID
INNER JOIN Detail d
ON p.PatternID = d.PatternID
WHERE r.Type = 7
AND d.Panel = 501
AND CAST(c.DT AS DATE)
BETWEEN '20190101' AND '20190201'
GROUP BY CAST(c.DT AS DATE)
ORDER BY CAST(c.DT AS DATE)
The query above isn't working for me. It still skips days where the COUNT is NULL for it's c.DT.
c.DT and p.PatternDate are both time DateTime, although c.DT can't be NULL. It is actually the PK for the table. It is populated as DateTimes for every single day from 2015 to 2049, so the records for those days exist.
Another weird thing I noticed is that nothing returns at all when I join C.DT = p.PatternDate without a CAST or CONVERT to a Date style. Not sure why when they are both DateTimes.
There are a few things to talk about here. At this stage it's not clear what you're actually trying to count. If it's the number of "patterns" per day for the month of Jan 2019, then:
Your BETWEEN will also count any activity occurring on 1 Feb,
It looks like one pattern could have multiple results, potentially causing a miscount
It looks like one pattern could have multiple details, potentially causing a miscount
If one pattern has say 3 eligible results, and also 4 details, you'll get the cross product of them. Your count will be 12.
I'm going to assume:
you only want the distinct number of patterns, regardless of the number of details and results.
You only want January's activity
--Set up some dummy data
DROP TABLE IF EXISTS #CalendarMain
SELECT cast('20190101' as datetime) as DT
INTO #CalendarMain
UNION ALL SELECT '20190102' as DT
UNION ALL SELECT '20190103' as DT
UNION ALL SELECT '20190104' as DT
UNION ALL SELECT '20190105' as DT --etc etc
;
DROP TABLE IF EXISTS #Pattern
SELECT cast('1'as int) as PatternID
,cast('20190101 13:00' as datetime) as PatternDate
INTO #Pattern
UNION ALL SELECT 2,'20190101 14:00'
UNION ALL SELECT 3,'20190101 15:00'
UNION ALL SELECT 4,'20190104 11:00'
UNION ALL SELECT 5,'20190104 14:00'
;
DROP TABLE IF EXISTS #Result
SELECT cast(100 as int) as ResultID
,cast(1 as int) as PatternID
,cast(7 as int) as [Type]
INTO #Result
UNION ALL SELECT 101,1,7
UNION ALL SELECT 102,1,8
UNION ALL SELECT 103,1,9
UNION ALL SELECT 104,2,8
UNION ALL SELECT 105,2,7
UNION ALL SELECT 106,3,7
UNION ALL SELECT 107,3,8
UNION ALL SELECT 108,4,7
UNION ALL SELECT 109,5,7
UNION ALL SELECT 110,5,8
;
DROP TABLE IF EXISTS #Detail
SELECT cast(201 as int) as DetailID
,cast(1 as int) as PatternID
,cast(501 as int) as Panel
INTO #Detail
UNION ALL SELECT 202,1,502
UNION ALL SELECT 203,1,503
UNION ALL SELECT 204,1,502
UNION ALL SELECT 205,1,502
UNION ALL SELECT 206,1,502
UNION ALL SELECT 207,2,502
UNION ALL SELECT 208,2,503
UNION ALL SELECT 209,2,502
UNION ALL SELECT 210,4,502
UNION ALL SELECT 211,4,501
;
-- create some variables
DECLARE #start_date as date = '20190101';
DECLARE #end_date as date = '20190201'; --I assume this is an exclusive end date
SELECT cal.DT
,isnull(patterns.[count],0) as [Count]
FROM #CalendarMain cal
LEFT JOIN ( SELECT cast(p.PatternDate as date) as PatternDate
,COUNT(DISTINCT p.PatternID) as [Count]
FROM #Pattern p
JOIN #Result r ON p.PatternID = r.PatternID
JOIN #Detail d ON p.PatternID = d.PatternID
WHERE r.[Type] = 7
and d.Panel = 501
GROUP BY cast(p.PatternDate as date)
) patterns ON cal.DT = patterns.patternDate
WHERE cal.DT >= #start_date
and cal.DT < #end_date --Your code would have included 1 Feb, which I assume was unintentional.
ORDER BY cal.DT
;
I have below select statement to fetch the data having CASE statement.
SELECT PK_ID
,MGR_ID
,EMP_ID
,CASE
WHEN msts.MGR_ID is null AND msts.EMP_ID is not null THEN
(SELECT 'A' from dual)
ELSE
(SELECT 'B' from dual)
END FIRST_COL
,CASE
WHEN msts.MGR_ID is null AND msts.EMP_ID is not null THEN
(SELECT 'P' from dual)
ELSE
(SELECT 'Q' from dual)
END SECOND_COL
,CASE
WHEN msts.MGR_ID is null AND msts.EMP_ID is not null THEN
(SELECT 'X' from dual)
ELIE
(SELECT 'Y' from dual)
END THIRID_COL
from m_sel_tabs msts
here, As i know that we can check condition with mulitiple columns but the result will be only one for CASE statement.
so my question is here that as my check CASE statement is the same for all three columns (FIRST_COL, SECOND_COL, THIRID_COL), hence is there any other way to write this query in an optimized way.
Thanks in advance.
Maybe I'm wrong, but - when saying that you have "the same 3 CASE statements" - well, you don't. Those are 3 different CASE statements. An expression is the same, yes, but you're selecting 3 different columns, with different results (A, B, P, Q, X, Y - in your example).
You could create a function which would "hide" code you currently use and make the SELECT prettier, such as
select
pk_id, ...,
f_col(1, MGR_ID, EMP_ID) first_col,
f_col(2, MGR_ID, EMP_ID) second_col,
f_col(3, MGR_ID, EMP_ID) third_col
from m_sel_tabs
but - at the end - it would be just the same (or, possibly somewhat worse because of context switching) as you'd have to put all that code somewhere (into the function, right?).