How select second max value from a subquery - sql

I need to select a max date (DATA_RIF_PATR_KU) for the key PROT, CODICE_COM, but there are also 9999-12-31 values. So when there are others date than 9999-12-31 I need to select the "real max date" else 9999-12-31.
For example:
For the combination:
PROT = '202000060300' AND
CODICE_COM='Z01'
I have 2 dates of DATA_RIF_PATR_KU: 03-11-20, 9999-12-31. I need to select the first one.
I wrote this code:
'''
SELECT
A.GRADO,
A.COMM,
A.PROT,
MAX(A.FLAG_VAL_IND) AS FLAG_VAL_IND,
SUM(A.CONT_VERS) AS CONT_VERS,
SUM(A.IMP_PREN) AS IMP_PREN,
SUM(A.CONT_DIFF) AS CONT_DIFF,
MIN(A.DATA_VER) AS DATA_VER,
MAX(A.PREN_DEB) AS PREN_DEB,
MAX(A.PREN_DEB_VER) AS PREN_DEB_VER,
MAX(A.GRAT_PATR_KU) AS GRAT_PATR_KU,
MAX(CASE WHEN (A.MAX_DATA_RIF_PATR_NON_9999)='SI' THEN A.DATA_RIF_PATR_KU
WHEN (A.MAX_DATA_RIF_PATR_NON_9999_2)='SI2' THEN A.DATA_RIF_PATR_KU END) AS DATA_RIF_PATR_KU,
SUM(A.MAGG_PEC) AS MAGG_PEC,
MAX(A.ASS_PEC) AS ASS_PEC,
MAX(A.ASS_CF) AS ASS_CF,
MAX(A.ASS_VAL) AS ASS_VAL,
MAX(A.FLAG_LAV) AS FLAG_LAV,
SUM(A.CONT_DIC) AS CONT_DIC,
SUM(A.CONT_TOT) AS CONT_TOT,
SUM(A.CONT_DIFF_VERIF) AS CONT_DIFF_VERIF,
MAX(A.DATA_AGG) AS DATA_ULTIMA_VALIDAZIONE,
MAX(CASE WHEN (A.DATA_INV)<'9999-12-31'
THEN '1'
ELSE '0' END) AS PRESENZA_INVITO_PAG,
MAX(CASE WHEN (A.DATA_VERS_INV)<'9999-12-31'
THEN '1'
ELSE '0' END) AS PRESENZA_VERS_INVITO
FROM
(
SELECT
distinct BILS05_GRADO AS GRADO,
BILS05_CODICE_COM AS COMM,
BILS05_PROT AS PROT,
CASE WHEN BILS05_FLAG_VAL_IND IN ('0','9')
THEN 'D'
ELSE 'I' END AS FLAG_VAL_IND,
bils05_tipo_doc, bils05_prog_alleg, bils05_pren_deb as pren_deb,
BILS05_PREN_DEB_VERIF AS PREN_DEB_VER,
CASE WHEN BILS05_PREN_DEB='1' AND BILS05_PREN_DEB_VERIF='1'
THEN 0
ELSE BILS05_CONT_VERS_VERIF END AS CONT_VERS,
CASE WHEN BILS05_PREN_DEB='1' AND BILS05_PREN_DEB_VERIF='1'
THEN BILS05_CONT_VERS_VERIF
ELSE 0 END AS IMP_PREN,
BILS05_CONT_DIFF AS CONT_DIFF,
BILS05_DATA_ACQ_KU AS DATA_VER,
BILS05_MAGG_PEC AS MAGG_PEC,
BILS05_ASS_PEC AS ASS_PEC,BILS05_ASS_CF AS ASS_CF,BILS05_ASS_VAL AS ASS_VAL,
BILS05_FLAG_LAV AS FLAG_LAV,
BILS05_CONT_VERS AS CONT_DIC,
BILS05_CONT_TOT AS CONT_TOT,
BILS05_CONT_DIFF_VERIF AS CONT_DIFF_VERIF,
BILS05_DATA_AGG_KU AS DATA_AGG,
BILS05_DATA_INV_PAG AS DATA_INV,
BILS05_DATA_VERS_INV AS DATA_VERS_INV,
BILS05_GRAT_PATR as GRAT_PATR_KU,
BILS05_DATA_RIF_PATR AS DATA_RIF_PATR_KU,
ROW_NUMBER() OVER(PARTITION BY BILS05_PROT, BILS05_CODICE_COM ORDER BY BILS05_DATA_RIF_PATR) AS RN,
LEAD(DATA_RIF_PATR_KU) OVER(PARTITION BY BILS05_PROT, BILS05_CODICE_COM ORDER BY DATA_RIF_PATR_KU) AS FOLLOW_DATA,
LAG(DATA_RIF_PATR_KU) OVER(PARTITION BY BILS05_PROT, BILS05_CODICE_COM ORDER BY DATA_RIF_PATR_KU) AS PREV_DATA,
CASE WHEN (DATA_RIF_PATR_KU < FOLLOW_DATA AND DATA_RIF_PATR_KU NOT = '9999-12-31' AND FOLLOW_DATA='9999-12-31' )THEN 'SI'
ELSE 'NO' END AS MAX_DATA_RIF_PATR_NON_9999,
CASE WHEN (DATA_RIF_PATR_KU NOT = '9999-12-31' AND FOLLOW_DATA IS NULL) OR (DATA_RIF_PATR_KU = '9999-12-31' AND FOLLOW_DATA IS NULL)
THEN 'SI2' ELSE 'NO' END AS MAX_DATA_RIF_PATR_NON_9999_2
FROM ZUCOW.BILS05
WHERE
BILS05_FLAG_LAV='2'
) A
WHERE
A.PROT='202000060300' AND
A.COMM='Z01'
GROUP BY A.GRADO, A.COMM, A.PROT;
'''
but it doesn't work properly. It select 9999-12-31 instead of 03-11-20 in the above example

Your example is rather long and complex, but the general idea would be
(assuming DATA_RIF_PATR_KU is a date field):
select
max(case when DATA_RIF_PATR_KU='9999-12-31' then null else DATA_RIF_PATR_KU end),
PROT, CODICE_COM
FROM FROM ZUCOW.BILS05
GROUP BY 2,3

yes that's the general idea.. Anyway at the end, I solved it in another way:
MAX(CASE WHEN TO_CHAR(A.DATA_RIF_PATR_KU, 'YYYY-MM-DD' ) LIKE ('9999-12-31')THEN '0000-12-31' ELSE TO_CHAR(A.DATA_RIF_PATR_KU, 'YYYY-MM-DD') END) AS DATA_RIF_PATR_KU_STR
So, I converted the 9999-12-31 values in 0000-12-31 (I had to to transform the date value in string), so then I could do the max and then I converted the values back in the ETL software.
Thank You all for helping

Related

How to present a particular SQL queried row as columns in output

I need to present the attached output in PIC1 as the result in PIC2. The query used for generating PIC1 output in SQLDeveloper:
select subs_nm, as_of_date, run_status, (select max (tp.pr_vl)
from ual_mng.tqueue tq, ual_mng.tparams tp, ual_mng.tstatus ts
WHERE tq.tid = tp.tid AND tq.tid = ts.tid and tq.run_id = pcm.run_id and tp.pr_nm in ('TOT_RECORD_CNT')) as RECORD_COUNT
from UAL_MNG.PCM_SUBS_RUN_DTL_VW pcm where SUBS_NM='S_TS2_AQUA_A1_RLAP_DL' and AS_OF_DATE in ('2021-09-01','2021-09-02') order by run_start_dtm desc;
Appreciate all help.
If you don't need it to be dynamic (ie. it will only be two columns and you know which two months they are) you can do
select subs_nm,
max(case when as_of_date = '2021-09-01' then RECORD_COUNT else 0 end) as SEP1,
max(case when as_of_date = '2021-09-02' then RECORD_COUNT else 0 end) as SEP2,
from (
-- Your query
)
group by subs_nm
You can work out the percentage difference using the same expressions.
nb. I would always use an explicit date format mask. This might not run on a different machine / software. So use to_date('2021-09-01', 'yyyy-mm-dd')
Posting the query, which worked in the script :
select subs_nm, SEP1, SEP2, round((((SEP1-SEP2)/SEP1)*100),2) as DIFF_PER from ( select subs_nm,
max(case when as_of_date='2021-09-01' then RECORD_COUNT else '0' end) as SEP1,
max(case when as_of_date='2021-09-02' then RECORD_COUNT else '0' end) as SEP2 from (-- *Main Query*);

Count sequence selected columns

I have query below, I want sequence result like the value of 'feb' will sum by jan and feb, value of 'mar' will sum by jan, feb and mar,... . Is there any way to get the result like that?
select A.location as location
, count(Case When SUBSTRING(A.base_date,5,2)='01' Then A.customer_no else null end) as "jan"
, count(Case When SUBSTRING(A.base_date,5,2)='02' Then A.customer_no else null end) as "feb"
....
, count(Case When SUBSTRING(A.base_date,5,2)='12' Then A.customer_no else null end) as "dec"
from table_income A group by A.location;
SQL is a much more effective language when you think in rows rather than columns (normalisation).
For example, having one row per month is much simpler...
SELECT
location,
SUBSTRING(base_date,5,2) AS base_month,
SUM(COUNT(customer_no))
OVER (
PARTITION BY location
ORDER BY SUBSTRING(base_date,5,2)
)
AS count_cust
FROM
table_income
GROUP BY
location,
SUBSTRING(base_date,5,2)
Side notes:
If your base_date is a string, it shouldn't be, use data-types relevant to the data
If your base_date is a date or timestamp, you should really use date/timestamp functions, such as EXTRACT(month FROM base_date).
You probably should also account for different years...
SELECT
location,
DATE_TRUNC('month', base_date) AS base_month,
SUM(COUNT(customer_no))
OVER (
PARTITION BY location, DATE_TRUNC('year', base_date)
ORDER BY DATE_TRUNC('month', base_date)
)
AS count_cust
FROM
table_income
GROUP BY
location,
DATE_TRUNC('month', base_date)
Try this :
SELECT A.location as location
, count(Case When SUBSTRING(A.base_date,5,2) in ('01') Then A.customer_no else null end) as "jan"
, count(Case When SUBSTRING(A.base_date,5,2) in ('01','02') Then A.customer_no else null end) as "feb"
....
, count(Case When SUBSTRING(A.base_date,5,2) in ('01','02',...'12') Then A.customer_no else null end) as "dec"
from table_income A group by A.location;

Sql out put which come into multiple row converted to single row

This query give multiple row which needs to be shown in single row. Please help.
SELECT blng_serv_code, (COUNT (blng_serv_code)) AS total ,
DECODE (package_trx_yn, 'Y', 'PKG', 'N', 'NPKG') pkg_status FROM bl_patient_charges_folio
WHERE operating_facility_id = 'MC'
AND trx_date >= TO_DATE ('10/10/2019 00:00:00', 'MM/DD/YYYY HH24:MI:SS')AND blng_serv_code = 'LBSB000015'
GROUP BY blng_serv_code, package_trx_yn
If you want the value in a single row, leave out the package status:
SELECT blng_serv_code, COUNT(*) AS total
FROM bl_patient_charges_folio
WHERE operating_facility_id = 'MC' AND
trx_date >= DATE '2019-10-10' AND
blng_serv_code = 'LBSB000015'
GROUP BY blng_serv_code;
If you do want the package status, then you need to explain the logic for including it "on a single row".
EDIT:
It sounds like you want the values in separate columns:
SELECT blng_serv_code, COUNT(*) AS total,
SUM(CASE WHEN package_trx_yn = 'Y' THEN 1 ELSE 0 END) as pkg_cnt,
SUM(CASE WHEN package_trx_yn = 'N' THEN 1 ELSE 0 END) as npkg_cnt
FROM bl_patient_charges_folio
WHERE operating_facility_id = 'MC' AND
trx_date >= DATE '2019-10-10' AND
blng_serv_code = 'LBSB000015'
GROUP BY blng_serv_code;

Tracking Changes in Retail Store Ownership Over Time

Sample Data Set and Desired Query Result
I have a list of retail stores that have changed ownership over time (from company owned, to licensed or franchised and back to company owned). I'm trying to track the count of stores open each month under each ownership type. For each change in ownership I have a new line item in the data set, each of which has a corresponding Start and End date for the change.
I'm trying to count the stores by ownership type for each month of the data and I'm having trouble figuring out how to count the stores for the all the months IN BETWEEN the dates of the ownership start and end dates. Hopefully the picture makes it perfectly clear what I'm looking to do.
select
b.fscl_yr_num
,b.fscl_per_in_yr_num
,a.ownr_type_cd
,sum(case when a.line_start_dt < b.end_dt and a.line_end_dt <= b.End_Dt then 1 else 0 end)
from
(
(
select *
from
(select
store_num
,ownr_type_cd
,case when store_term_dt is not null then 'Closed' else 'Open' end as Status
,case when to_date(trim(store_open_dt),'DD-MON-YY') > to_date(trim(eff_from_dt),'DD-MON-YY') then to_date(trim(store_open_dt),'DD-MON-YY') else to_date(trim(eff_from_dt),'DD-MON-YY') end as Line_Start_Dt
,case when store_term_dt is null then eff_to_dt
when to_date(trim(store_term_dt),'DD-MON-YY') < to_date(trim(eff_to_dt),'DD-MON-YY') then to_date(trim(store_term_dt),'DD-MON-YY') else to_date(trim(eff_to_dt),'DD-MON-YY') end as Line_End_Dt
from
(select
store_num
,store_open_dt
,store_term_dt
,eff_from_dt
,eff_to_dt
,ownr_type_cd
from
appca.d_store_vers
where
upper(cntry_cd_2_dgt_iso) = 'GB'
and postal_cd not like ('BT%')
and store_open_dt is not null
group by
store_num
,store_open_dt
,store_term_dt
,eff_from_dt
,eff_to_dt
,ownr_type_cd
order by
store_num
,eff_from_dt)
group by
store_num
,ownr_type_cd
,case when store_term_dt is not null then 'Closed' else 'Open' end
,case when to_date(trim(store_open_dt),'DD-MON-YY') > to_date(trim(eff_from_dt),'DD-MON-YY') then to_date(trim(store_open_dt),'DD-MON-YY') else to_date(trim(eff_from_dt),'DD-MON-YY') end
,case when store_term_dt is null then eff_to_dt
when to_date(trim(store_term_dt),'DD-MON-YY') < to_date(trim(eff_to_dt),'DD-MON-YY') then to_date(trim(store_term_dt),'DD-MON-YY') else to_date(trim(eff_to_dt),'DD-MON-YY') end
order by
1 asc
,2 asc
,3 asc)
where
to_date(trim(line_start_dt),'DD-MON-YY') < to_date(trim(line_end_dt),'DD-MON-YY')
) A
right join
--Calendar Table--
(
select
fscl_yr_num, fscl_per_in_yr_num, Cal_dt min(to_date(trim(cal_dt),'DD-MON-YY')) as Start_Dt, max(to_date(trim(cal_dt),'DD-MON-YY')) as End_Dt
from
appca.d_cal
where
fscl_yr_num is between 1990 and 2018
group by
fscl_yr_num, fscl_per_in_yr_num
order by
1 asc, 2 asc
) B
on A.line_end_dt = B.cal_dt
)
group by
b.fscl_yr_num
,b.fscl_per_in_yr_num
,a.ownr_type_cd
order by
b.fscl_yr_num
,b.fscl_per_in_yr_num
;
Try this case:
sum(case when createTime >(cast(year(createTime) as varchar) +'-'+cast( MONTH(createTime) as varchar)+'-1') and createTime <(cast(year(createTime) as varchar) +'-'+cast( MONTH(createTime) as varchar)+'-31')
then 1 else 0 end) 'Company'

sqlite select: grouping in one line, 12 entries

I have a table with fields:
Client_ID, Date, Value
where there is an entry for each of the 12 months of a year (i.e., 12 entries for each client).
I would like to create a table with just one row per Client_ID that contains all the values from each months. Something like:
Client_ID, Date_January, Value_January, Date_February, Value_February, ........, Date_December, Value_December
Can anyone help me with the query?
This is what I'm trying to do (not working...):
select
Client_Id,
case when ((strftime('%m', Date) = '01')) then
Date as Date_January,
Value as Value_January,
else null end
case when ((strftime('%m', Date) = '01')) then
Date as Date_February,
Value as Value_February,
else null end
....
from Test_Table
where
strftime('%Y', Date) = '2013'
;
First you need to untangle your case constructs as they generate a single value. Use:
case
when ((strftime('%m', Date) = '01')) then Date
else null
end as Date_January,
case when ((strftime('%m', Date) = '01')) then Value
else null
end as Value_January,
Then, if you want one row per client, use GROUP BY ClientID.
The third issue is how to aggregate all the Date_January columns into one row. If you really know that there is exactly one row per month per client, you can use MAX() knowing that the not null value will be higher than the NULL values:
select
Client_Id,
MAX(case
when ((strftime('%m', Date) = '01')) then Date
else null
end) as Date_January,
MAX(case when ((strftime('%m', Date) = '01')) then Value
else null
end) as Value_January,
MAX(case
when ((strftime('%m', Date) = '02')) then Date
else null
end) as Date_February,
MAX(case when ((strftime('%m', Date) = '02')) then Value
else null
end) as Value_February,
....
from Test_Table
where
strftime('%Y', Date) = '2013'
group by Client_Id;