SQL Concat and convert date to MM/YYYY - sql

Newbie here. Thanking you in advance for your help!
I have the following code to count unique records based on 3 data elements:
count(distinct concat(a.emp_nbr, b.acct_nbr, c.event_dt))
The event_dt is stored in the db as [DATE].
the issue is that i don't want to EXCLUDE 'DD' in the concat match statement. I want to match based on the MM/YYYY only. I believe the answer is to convert the [DATE] to MM/YYYY.
Ultimately i want to count distinct records based on emp_nbr, acct_nbr and mm/yyyy of event_dt.
Thanks!
MODIFIED
here is the query:
select distinct
B.emp_nbr, A.cust_nbr, E.cntry_enti_nbr, A.event_dt,
count(distinct concat(B.emp_nbr, E.cntry_enti_nbr, A.event_dt))
from customer A
left join user_profile B on A.owner_ID = B.owner_ID
left join account_owner E on A.cust_nbr = E.cust_nbr
where CAST(A.ramp_dt AS date format 'MM/DD/YYYY') between '01/01/2020' and '08/31/2020'
group by 1,2,3,4
Here's a sample of the results that are returned:
ln...emp_nbr.....cust_nbr.....ctry_enti_nbr event_dt......'Unique Identifier'
1....123.........87543290......488807........5/15/2020.........1
2....123.........62524497......488807........2/28/2020.........1 **
3....123.........62524497......488807........2/26/2020.........1 **
4....789.........62524497......488807........2/26/2020.........1
5....876.........62524497......488807........2/26/2020.........1
Line 2 or 3 should NOT be flagged as '1' (unique)
EDIT: changed code based on dnoeth's reco to add the count(*) OVER (PARTITION):
select distinct
B.emp_nbr, A.cust_nbr, E.cntry_enti_nbr, A.event_dt,
to_char(A.event_dt, 'YYYYMM') as Event_Month,
case when COUNT(*) OVER (PARTITION BY B.emp_nbr, A.cntry_enti_nbr, Event_Month)
= 1 then 1 else 0 end as Unique_Monthly_Event
from customer A
left join user_profile B on A.owner_ID = B.owner_ID
left join account_owner E on A.cust_nbr = E.cust_nbr
where CAST(A.event_dt AS date format 'MM/DD/YYYY') between '01/01/2020' and '08/31/2020'
group by 1,2,3,4
works fine for the previous case, however in another case it shows all ZERO for unique:
ln...emp_nbr.....cust_nbr.....ctry_enti_nbr event_dt......'Unique Identifier'
1....123.........78473466......863429........5/31/2020.........0
2....123.........78473466......863429........5/29/2020.........0
3....123.........78473466......863429........5/5/2020..........0
I would like to see ONE record with a unique identifier of "1"

Line 2 or 3 should NOT be flagged as '1' (unique)
... because there's more than one row per emp_nbr/cust_nbr/ctry_enti_nbr?
Then you need a simple Group Count:
select
B.emp_nbr, A.cust_nbr, E.cntry_enti_nbr, A.event_dt,
-- I would like to see ONE record with a unique identifier of "1"
-- this returns the row with the latest event date
case
when row_number()
over (partition by B.emp_nbr, A.cust_nbr, E.cntry_enti_nbr
order by event_dt desc) = 1
then 1
else 0
end
from customer A
left join user_profile B on A.owner_ID = B.owner_ID
left join account_owner E on A.cust_nbr = E.cust_nbr
where CAST(A.ramp_dt AS date format 'MM/DD/YYYY') between '01/01/2020' and '08/31/2020'
group by 1,2,3,4

You can simply use EXTRACT() function to extract year and month from the date. For example:
SELECT COUNT(DISTINCT CONCAT(a.emp_nbr, b.acct_nbr, EXTRACT(YEAR FROM c.event_dt), EXTRACT(MONTH FROM c.event_dt)))
FROM ...

You can use to_char(). Something like this:
count(distinct concat(a.emp_nbr, '|', b.acct_nbr, '|', to_char(c.event_dt, 'YYYYMM'))
or more commonly:
count(distinct a.emp_nbr || '|' || b.acct_nbr || '|' || to_char(c.event_dt, 'YYYYMM')
Note that this also puts a delimiter between
Your query looks off. I think you just want:
select A.cust_nbr, E.cntry_enti_nbr, to_char(c.event_dt, 'YYYYMM'),
count(*)
from customer A left join
user_profile B
on A.owner_ID = B.owner_ID left join
account_owner E
on A.cust_nbr = E.cust_nbr
where CAST(A.ramp_dt AS date format 'MM/DD/YYYY') between '01/01/2020' and '08/31/2020'
group by A.cust_nbr, E.cntry_enti_nbr, to_char(c.event_dt, 'YYYYMM');

Related

Error 00937 "not a single-group group function"

i face ORA-00937: "not a single-group group function" error problem with this sql query:
Any ideas please ! Thanks.
SELECT avg(count(*)) as value, 'Taux remplissage' as serie, to_char(c.datcre, 'YYYY-MM-DD') as arg
from charge c left join emplac e ON c.adr = e.adr
where e.ADR is not null and e.empsta != 'I' and e.empsta != 'V'
and (trunc(c.datcre) >= to_date('2020-11-01','YYYY-MM-DD'))
and (trunc(c.datcre) <= to_date('2021-11-30','YYYY-MM-DD'))
GROUP BY to_char(c.datcre, 'YYYY-MM-DD')
ORDER BY arg, serie
I'm not sure what you mean by avg(count(*)) in this context. This would be used (in Oracle) in a context where you want a result set with one row. But the order by suggests that you are expecting multiple rows.
If you just want the count(*) then you would use:
select count(*) as value, 'Taux remplissage' as serie,
to_char(c.datcre, 'YYYY-MM-DD') as arg
from charge c join
emplac e
ON c.adr = e.adr
where e.ADR is not null and e.empsta not in ('I', 'V') and
c.datcre >= date '2020-11-01' and
c.datcre < date '2021-12-01'
group by to_char(c.datcre, 'YYYY-MM-DD')
order by arg;
If you want the overall average on every row, you would use:
avg(count(*)) over () as average
Note the other changes to the query:
not in is much simpler than a chain of <>s.
Strictly speaking, the is not null is redundant, but I left it in.
The where clause turns the left join into an inner join anyway, so you should specify the join you are actually using.
Oracle supports the Standard SQL syntax for date constants. You might as well use it.
The date comparisons are generally going to be more efficient when you remove functions on the column. That helps the optimizer.
SELECT count(*) * 100.0 / (select count(*) from emplac) as value,'% remplissage ' || c.mag as serie, to_char(c.datcre, 'YYYY-MM-DD') as arg
from charge c left join emplac e ON c.adr = e.adr
where e.ADR is not null and e.empsta != 'I'
and (trunc(c.datcre) >= to_date('2020-11-01','YYYY-MM-DD'))
and (trunc(c.datcre) <= to_date('2021-11-30','YYYY-MM-DD'))
GROUP BY to_char(c.datcre, 'YYYY-MM-DD'), c.mag
ORDER BY arg

How to select data without using group?

My base data based on dealer code only but in one condition we need to select other field as well to matching the condition in other temp table how can i retrieve data only based on dealercode ith matching the condition on chassis no.
Below is the sample data:
This is how we have selected the data for the requirement:
---------------lastyrRenewalpolicy------------------
IF OBJECT_ID('TEMPDB..#LASTYRETEN') IS NOT NULL DROP TABLE #LASTYRETEN
select DEALERMASTERCODE , count(*) RENEWALEXPRPOLICY,SUM(NETOD_YEAR_PREM_PART_A) AS 'ACHIEVED-ODPREMIUM_RENEWAL' into #LASTYRETEN
from [dbo].[T_RE_POLICY_TRANSACTION]
where cast (InsPolicyCreatedDate as date) between #FirstDayC and #LastDayC
AND PolicyStatus= 'Renewal' AND (ltrim(rtrim(ISCANCELLEDSTATUS)) = 0 ) group by DEALERMASTERCODE
-----------------lastrollower------------------------
IF OBJECT_ID('TEMPDB..#LASTYROLWR') IS NOT NULL DROP TABLE #LASTYROLWR
select DEALERMASTERCODE , count(*) ROLLOWEEXPRPOLICY ,SUM(NETOD_YEAR_PREM_PART_A) AS 'ACHIEVED-ODPREMIUM_ROLLOVER'
into #LASTYROLWR from [dbo].[T_RE_POLICY_TRANSACTION] where cast (InsPolicyCreatedDate as date) between #FirstDayC and #LastDayC
AND PolicyStatus= 'ROLLOVER' AND (ltrim(rtrim(ISCANCELLEDSTATUS)) = 0 ) group by DEALERMASTERCODE
And continue with above flow Below is the other select statement which creating issue at the end due to grouping
:
-------------OTHERYRBASE(EXPIRYRENEWAL)--------------
IF OBJECT_ID('TEMPDB..#OTHERYRBASEEXPIRY') IS NOT NULL DROP TABLE #OTHERYRBASEEXPIRY
select DEALERMASTERCODE ,ChassisNo , count(*) RENEWALPOLICYEXPIRY
into #OTHERYRBASEEXPIRY
from [dbo].[T_RE_POLICY_TRANSACTION] where cast (PolicyExpiryDate as date) between '2020-08-01' and '2020-08-31'
and BASIC_PREM_TOTAL <> 0 AND PolicyStatus in ('Renewal','rollover') and BusinessType='jcb'
AND (ltrim(rtrim(ISCANCELLEDSTATUS)) = 0 ) group by DEALERMASTERCODE,ChassisNo
-------------OTHERYRBASE(EXPIRYRENEWAL)--------------
IF OBJECT_ID('TEMPDB..#OTHERYRCON') IS NOT NULL DROP TABLE #OTHERYRCON
select OTE.DEALERMASTERCODE ,OTE.ChassisNo , count(*) OTHERYRCON into #OTHERYRCON
from [dbo].[T_RE_POLICY_TRANSACTION] OTE INNER JOIN #OTHERYRBASEEXPIRY EXP
ON OTE.ChassisNo=EXP.ChassisNo
where cast(CREATED_DATE as date) between '2020-06-01' and '2020-12-31' and BusinessType='jcb'
and OTE.BASIC_PREM_TOTAL <> 0 AND OTE.PolicyStatus = 'Renewal'
AND (ltrim(rtrim(ISCANCELLEDSTATUS)) = 0 ) group by OTE.DEALERMASTERCODE,OTE.ChassisNo
Thanks a lot in advance for helping and giving a solution very quickly ///
After taking a look at this code it seems possible there was an omitted JOIN condition in the last SELECT statement. In the code provided the JOIN condition is only on ChassisNo. The GROUP BY in the prior queries which populates the temporary table also included the DEALERMASTERCODE column. I'm thinking DEALERMASTERCODE should be added to the JOIN condition. Something like this
select OTE.DEALERMASTERCODE ,OTE.ChassisNo , count(*) OTHERYRCON
into #OTHERYRCON
from [dbo].[T_RE_POLICY_TRANSACTION] OTE
INNER JOIN #OTHERYRBASEEXPIRY EXP ON OTE.DEALERMASTERCODE=EXP.DEALERMASTERCODE
and OTE.ChassisNo=EXP.ChassisNo
where cast(CREATED_DATE as date) between '2020-06-01' and '2020-12-31'
and BusinessType='jcb'
and OTE.BASIC_PREM_TOTAL <> 0
AND OTE.PolicyStatus = 'Renewal'
AND (ltrim(rtrim(ISCANCELLEDSTATUS)) = 0 )
group by OTE.DEALERMASTERCODE,OTE.ChassisNo;

SQL Oracle Query - Left Outer Join on null Field

I have this query
SELECT *
FROM (SELECT mi.visit_id, mi.event_id, mi.patient_id, mi.mrn, mi.reg_date,
mi.d_date, mi.bml_count, mi.TYPE, mblp.baby_patient_id,
mblp.baby_birthdate
FROM ajmid.km0076_motherinfo_test mi LEFT JOIN alfayezb2.mbl_patients mblp
ON mblp.mother_patient_id = mi.patient_id
--works here
AND ( TO_CHAR (mblp.baby_birthdate, 'mm/dd/YYYY') =
TO_CHAR (mi.reg_date, 'mm/dd/YYYY')
OR TO_CHAR (mblp.baby_birthdate, 'mm/dd/YYYY') =
TO_CHAR (mi.reg_date - 1, 'mm/dd/YYYY')
OR TO_CHAR (mblp.baby_birthdate, 'mm/dd/YYYY') =
TO_CHAR (mi.reg_date + 1, 'mm/dd/YYYY')
)
) bml
LEFT OUTER JOIN --doesn't work here
(SELECT ROW_NUMBER () OVER (PARTITION BY vis.patient_id ORDER BY vis.admission_date_time)
num,
vis.admission_date_time, vis.visit_id, vis.patient_id,
vis.facility_id
FROM visit vis) v ON bml.baby_patient_id = v.patient_id
WHERE v.num = 1
ORDER BY bml.reg_date
bml by itself returns 118 rows while the whole query returns 117, the reason is bml returns 1 row with baby_patient_id as null, so I used left outer join to show it, but it's still not showing !!
what can I do to show all rows of bml ?
I'm using Toad 9.6
Thank you
check the query:
SELECT ROW_NUMBER () OVER (PARTITION BY vis.patient_id ORDER BY vis.admission_date_time)
num,
vis.admission_date_time, vis.visit_id, vis.patient_id,
vis.facility_id
FROM visit vis
does it return 118 not null patient_id's?
if it returns 117, that might be the reason.(LEFT OUTER JOIN doesnot pick the records which are null on both tables)
Also, are you sure the null value of baby_patient_id in bml table is actually a NULL value and not a empty charater?(' ').
The probable cause is your filter / criteria (where clause) is eliminating a row with a null value for v.num. The WHERE filters the results after the join.
WHERE v.num = 1 -- Are all v.num equal to 1 ?
The mere action of using a criteria against a field, by definition of what NULL means, eliminates that row from consideration because NULL cannot be evaluated. You can say "WHERE id != 1" and expect to get rows where id is null because null != 1 right? Wrong. id != NULL is not defined logically. It is why we say "IS or IS NOT NULL" when dealing with NULL.
it's working finally !
I added
OR bml.baby_patient_id IS NULL
to the where clause, so the final script is
SELECT *
FROM (SELECT mi.visit_id, mi.event_id, mi.patient_id, mi.mrn, mi.reg_date,
mi.d_date, mi.bml_count, mi.TYPE, mblp.baby_patient_id,
mblp.baby_birthdate
FROM ajmid.km0076_motherinfo_test mi LEFT JOIN alfayezb2.mbl_patients mblp
ON mblp.mother_patient_id = mi.patient_id
AND ( TO_CHAR (mblp.baby_birthdate, 'mm/dd/YYYY') =
TO_CHAR (mi.reg_date, 'mm/dd/YYYY')
OR TO_CHAR (mblp.baby_birthdate, 'mm/dd/YYYY') =
TO_CHAR (mi.reg_date - 1, 'mm/dd/YYYY')
OR TO_CHAR (mblp.baby_birthdate, 'mm/dd/YYYY') =
TO_CHAR (mi.reg_date + 1, 'mm/dd/YYYY')
)
) bml
LEFT OUTER JOIN
(SELECT ROW_NUMBER () OVER (PARTITION BY vis.patient_id ORDER BY vis.admission_date_time)
num,
vis.admission_date_time, vis.visit_id, vis.patient_id,
vis.facility_id
FROM visit vis) v ON bml.baby_patient_id = v.patient_id
WHERE v.num = 1
OR bml.baby_patient_id IS NULL
ORDER BY bml.reg_date
I don't know how this was helpful, I wish someone would explain for me !
Thanks all

What's the proper SQL query to find a 'status change' before given date?

I have a table of logged 'status changes'. I need to find the latest status change for a user, and if it was a) a certain 'type' of status change (s.new_status_id), and b) greater than 7 days old (s.change_date), then include it in the results. My current query sometimes returns the second-to-latest status change for a given user, which I don't want -- I only want to evaluate the last one.
How can I modify this query so that it will only include a record if it is the most recent status change for that user?
Query
SELECT DISTINCT ON (s.applicant_id) s.applicant_id, a.full_name, a.email_address, u.first_name, s.new_status_id, s.change_date, a.applied_class
FROM automated_responses_statuschangelogs s
INNER JOIN application_app a on (a.id = s.applicant_id)
INNER JOIN accounts_siuser u on (s.person_who_modified_id = u.id)
WHERE now() - s.change_date > interval '7' day
AND s.new_status_id IN
(SELECT current_status
FROM application_status
WHERE status_phase_id = 'In The Flow'
)
ORDER BY s.applicant_id, s.change_date DESC, s.new_status_id, s.person_who_modified_id;
You can use row_number() to filter one entry per applicant:
select *
from (
select row_number() over (partition by applicant_id
order by change_date desc) rn
, *
from automated_responses_statuschangelogs
) as lc
join application_app a
on a.id = lc.applicant_id
join accounts_siuser u
on lc.person_who_modified_id = u.id
join application_status stat
on lc.new_status_id = stat.current_status
where lc.rn = 1
and stat.status_phase_id = 'In The Flow'
and lc.change_date < now() - interval '7' day

sql db2 select records from either table

I have an order file, with order id and ship date. Orders can only be shipped monday - friday. This means there are no records selected for Saturday and Sunday.
I use the same order file to get all order dates, with date in the same format (yyyymmdd).
i want to select a count of all the records from the order file based on order date... and (i believe) full outer join (or maybe right join?) the date file... because i would like to see
20120330 293
20120331 0
20120401 0
20120402 920
20120403 430
20120404 827
etc...
however, my sql statement is still not returning a zero record for the 31st and 1st.
with DatesTable as (
select ohordt "Date" from kivalib.orhdrpf
where ohordt between 20120315 and 20120406
group by ohordt order by ohordt
)
SELECT ohscdt, count(OHTXN#) "Count"
FROM KIVALIB.ORHDRPF full outer join DatesTable dts on dts."Date" = ohordt
--/*order status = filled & order type = 1 & date between (some fill date range)*/
WHERE OHSTAT = 'F' AND OHTYP = 1 and ohscdt between 20120401 and 20120406
GROUP BY ohscdt ORDER BY ohscdt
any ideas what i'm doing wrong?
thanks!
It's because there is no data for those days, they do not show up as rows. You can use a recursive CTE to build a contiguous list of dates between two values that the query can join on:
It will look something like:
WITH dates (val) AS (
SELECT CAST('2012-04-01' AS DATE)
FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT Val + 1 DAYS
FROM dates
WHERE Val < CAST('2012-04-06' AS DATE)
)
SELECT d.val AS "Date", o.ohscdt, COALESCE(COUNT(o.ohtxn#), 0) AS "Count"
FROM dates AS d
LEFT JOIN KIVALIB.ORDHRPF AS o
ON o.ohordt = TO_CHAR(d.val, 'YYYYMMDD')
WHERE o.ohstat = 'F'
AND o.ohtyp = 1