Best practice when using same query repeatedly - sql

what is the alternative for using same query repeatedly many times. I want to store the query in some place and call it whenever I need it.
I'm computing 4 formulas: MTD sales, MTD previous year sales, MAT sales, MAT previus year sales as separate columns for 5 different products: A,B,C,D,E. along with some static conditions like account details should be provided and direct sales
I'm querying Case statements 4 (for formulas)* 5 (for products) times to define formula with static conditions for all 5 products. i.e. almost 80% of my query is repeated for 4*5 =20 times. Instead of repeating 80% of the query for all 20 times, is there any better way to do it. Kindly note, I don't have to store value of the query as function, instead can I store the repeated portion of the query and call it where ever I need?
Code:
SELECT A1.*,
-- MTD FOR PRODUCTS A,B,C,D
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='A'
AND
(EXTRACT (MONTH FROM DATE_MONTH)=EXTRACT(MONTH FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A))
AND
EXTRACT (YEAR FROM DATE_MONTH)=EXTRACT(YEAR FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A)))
THEN SALES ELSE 0 END AS MTD_PRODUCT_A,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='B'
AND
(EXTRACT (MONTH FROM DATE_MONTH)=EXTRACT(MONTH FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A))
AND
EXTRACT (YEAR FROM DATE_MONTH)=EXTRACT(YEAR FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A)))
THEN SALES ELSE 0 END AS MTD_PRODUCT_B,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='C'
AND
(EXTRACT (MONTH FROM DATE_MONTH)=EXTRACT(MONTH FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A))
AND
EXTRACT (YEAR FROM DATE_MONTH)=EXTRACT(YEAR FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A)))
THEN SALES ELSE 0 END AS MTD_PRODUCT_C,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='D'
AND
(EXTRACT (MONTH FROM DATE_MONTH)=EXTRACT(MONTH FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A))
AND
EXTRACT (YEAR FROM DATE_MONTH)=EXTRACT(YEAR FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A)))
THEN SALES ELSE 0 END AS MTD_PRODUCT_D,
---MTD LAST YEAR FOR PRODUCTS A,B,C,D
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='A'
AND
(EXTRACT (MONTH FROM DATE_MONTH)=EXTRACT(MONTH FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A))
AND
EXTRACT (YEAR FROM DATE_MONTH)=(SELECT EXTRACT(YEAR FROM MAX(SHOWN_DATE))-1 FROM TABLE_A))
THEN SALES ELSE 0 END AS MTD_PY_PRODUCT_A,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='B'
AND
(EXTRACT (MONTH FROM DATE_MONTH)=EXTRACT(MONTH FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A))
AND
EXTRACT (YEAR FROM DATE_MONTH)=(SELECT EXTRACT(YEAR FROM MAX(SHOWN_DATE))-1 FROM TABLE_A))
THEN SALES ELSE 0 END AS MTD_PY_PRODUCT_B,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='C'
AND
(EXTRACT (MONTH FROM DATE_MONTH)=EXTRACT(MONTH FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A))
AND
EXTRACT (YEAR FROM DATE_MONTH)=(SELECT EXTRACT(YEAR FROM MAX(SHOWN_DATE))-1 FROM TABLE_A))
THEN SALES ELSE 0 END AS MTD_PY_PRODUCT_C,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='D'
AND
(EXTRACT (MONTH FROM DATE_MONTH)=EXTRACT(MONTH FROM (SELECT MAX(SHOWN_DATE) FROM TABLE_A))
AND
EXTRACT (YEAR FROM DATE_MONTH)=(SELECT EXTRACT(YEAR FROM MAX(SHOWN_DATE))-1 FROM TABLE_A))
THEN SALES ELSE 0 END AS MTD_PY_PRODUCT_D,
----MAT SALES FOR PRODUCT A,B,C,D
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='A'
AND
(Date_Month between add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-11)
and
trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'))
THEN SALES ELSE 0 END AS MAT_PRODUCT_A,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='B'
AND
(Date_Month between add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-11)
and
trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'))
THEN SALES ELSE 0 END AS MAT_PRODUCT_B,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='C'
AND
(Date_Month between add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-11)
and
trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'))
THEN SALES ELSE 0 END AS MAT_PRODUCT_C,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='D'
AND
(Date_Month between add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-11)
and
trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'))
THEN SALES ELSE 0 END AS MAT_PRODUCT_D,
---MAT LAST YEAR SALES FOR PRODUCTS A,B,C,D
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='A'
AND
(Date_Month between add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-23)
and
add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-12))
THEN SALES ELSE 0 END AS MAT_PRODUCT_A,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='B'
AND
(Date_Month between add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-23)
and
add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-12))
THEN SALES ELSE 0 END AS MAT_PRODUCT_B,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='C'
AND
(Date_Month between add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-23)
and
add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-12))
THEN SALES ELSE 0 END AS MAT_PRODUCT_C,
CASE WHEN
ACCOUNT<> 'Not Provided' AND TYPE<> 'DIRECT' and PRODUCT='D'
AND
(Date_Month between add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-23)
and
add_months(trunc((SELECT MAX(Date_Month) AS MAX_DATE_DIST FROM TABLE_A),'month'),-12))
THEN SALES ELSE 0 END AS MAT_PRODUCT_D
FROM TABLE_A A1

There are several options.
If the underlying data only needs to be created periodically -- say, once per day or once per week, then you can schedule a job and create a table. This is probably the most common solution across different databases for complicated queries.
If the query itself is not particularly complicated or if you need up-to-date data every time, then use a (regular) view. This is the built-in functionality for encapsulating queries.
Another alternative is a materialized view. These are like tables, in that the data does not need to be (explicitly) recalculated. These are like views, in that the data is kept up-to-date. You can learn more about them in the documentation.

Use an analytical function to find the maximum date value:
SELECT A1.*,
CASE
WHEN ACCOUNT<> 'Not Provided'
AND TYPE<> 'DIRECT'
AND PRODUCT='A'
AND date_month_trunc = max_date_month
THEN SALES
ELSE 0
END AS MTD_PRODUCT_A,
/* B, C, D */
CASE
WHEN ACCOUNT <> 'Not Provided'
AND TYPE<> 'DIRECT'
AND PRODUCT='A'
AND date_month_trunc = max_date_month - INTERVAL '1' YEAR
THEN SALES
ELSE 0
END AS MTD_PY_PRODUCT_A,
/* B, C, D */
CASE
WHEN ACCOUNT<> 'Not Provided'
AND TYPE<> 'DIRECT'
AND PRODUCT='A'
AND date_month BETWEEN ADD_MONTHS( max_date_month - 11 ) AND max_date_month
THEN SALES
ELSE 0
END AS MAT_PRODUCT_A,
/* B, C, D */
CASE
WHEN ACCOUNT<> 'Not Provided'
AND TYPE<> 'DIRECT'
AND PRODUCT='A'
AND date_month BETWEEN ADD_MONTHS( max_date_month, -23 ) AND ADD_MONTHS( max_date_month, -12 )
THEN SALES
ELSE 0
END AS MAT_PRODUCT_A
/* B, C, D */
FROM (
SELECT a.*,
TRUNC( date_month, 'MM' ) AS date_month_trunc,
MAX( TRUNC( date_month, 'MM' ) ) OVER () AS max_date_month
FROM TABLE_A a
) A1
You could make it even shorter by moving common elements of the CASE to the sub-query:
SELECT A1.*,
CASE
WHEN PRODUCT='A'
AND date_month_trunc = max_date_month
THEN not_provided_direct_sales
ELSE 0
END AS MTD_PRODUCT_A,
/* B, C, D */
CASE
WHEN PRODUCT='A'
AND date_month_trunc = max_date_month - INTERVAL '1' YEAR
THEN not_provided_direct_sales
ELSE 0
END AS MTD_PY_PRODUCT_A,
/* B, C, D */
CASE
WHEN PRODUCT='A'
AND date_month BETWEEN ADD_MONTHS( max_date_month - 11 ) AND max_date_month
THEN not_provided_direct_sales
ELSE 0
END AS MAT_PRODUCT_A,
/* B, C, D */
CASE
WHEN PRODUCT='A'
AND date_month BETWEEN ADD_MONTHS( max_date_month, -23 ) AND ADD_MONTHS( max_date_month, -12 )
THEN not_provided_direct_sales
ELSE 0
END AS MAT_PRODUCT_A
/* B, C, D */
FROM (
SELECT a.*,
CASE
WHEN ACCOUNT<> 'Not Provided'
AND TYPE<> 'DIRECT'
THEN SALES
ELSE 0
END AS not_provided_direct_sales,
TRUNC( date_month, 'MM' ) AS date_month_trunc,
MAX( TRUNC( date_month, 'MM' ) ) OVER () AS max_date_month
FROM TABLE_A a
) A1

Related

SQL Query to give output in one row

I have created the below query -
select person_number
,sal.current_salary
,(CASE WHEN '2021-03-31' between to_char(sal.date_From ,'YYYY-MM-DD')
AND to_char(sal.date_to ,'YYYY-MM-DD')
THEN SALARY_AMOUNT
else
null
END) "2019_sal"
,(CASE WHEN '2020-03-31' between to_char(sal.date_From ,'YYYY-MM-DD')
AND to_char(sal.date_to ,'YYYY-MM-DD')
THEN SALARY_AMOUNT
else
null
END) "2020_sal"
,(CASE WHEN '2019-03-31' between to_char(sal.date_From ,'YYYY-MM-DD')
AND to_char(sal.date_to ,'YYYY-MM-DD')
THEN SALARY_AMOUNT
else
null
END) "2019_sal"
from per_all_people_f papf,
comp_salary sal
where papf.person_id = sal.person_id
and papf.person_number = :p_emp_number
and trunc(sysdate) between papf.effective_start_date and papf.effective_end_date
This gives me output like -
Person_number Current_salary 2019_sal 2020_sal
10 292929
10 287226
10 300000
11 282726
11 278090
Is there anyway i can tweak the above query to give me the output like -
Person_number Current_salary 2019_sal 2020_sal
10 292929 287226 300000
11 282726 278090
I.e. get the data against and employee in a single row. Can I use any function for this ?
Use simple aggregation to get the "MAX" value in each column for each person then group by that person. This will collapse each value into 1 record for each person number. It does however assume there will always only be 1 value for each column for a given person_number. Based on sample data; that appears to be the case.
select person_number
,max(sal.current_salary) "current_Salary"
,max(CASE WHEN '2021-03-31' between to_char(sal.date_From ,'YYYY-MM-DD')
AND to_char(sal.date_to ,'YYYY-MM-DD')
THEN SALARY_AMOUNT
else
null
END) "2019_sal"
,max(CASE WHEN '2020-03-31' between to_char(sal.date_From ,'YYYY-MM-DD')
AND to_char(sal.date_to ,'YYYY-MM-DD')
THEN SALARY_AMOUNT
else
null
END) "2020_sal"
,max(CASE WHEN '2019-03-31' between to_char(sal.date_From ,'YYYY-MM-DD')
AND to_char(sal.date_to ,'YYYY-MM-DD')
THEN SALARY_AMOUNT
else
null
END) "2019_sal"
from per_all_people_f papf,
comp_salary sal
where papf.person_id = sal.person_id
and papf.person_number = :p_emp_number
and trunc(sysdate) between papf.effective_start_date and papf.effective_end_date
GROUP BY person_number

PIVOT by timestamp

I need to pivot the time (hour) for the results of this query, so there could be up to 24 hours running across the top as you can replicate in an Excel pivot table. Is there an easy and efficient way to replicate this in the query?
Query:
SELECT
trunc(complete_dstamp) "Date",
to_char(complete_dstamp, 'HH24') "Hour",
user_id "User",
sum(update_qty) "Qty"
FROM
inventory_transaction
WHERE
to_loc_id = 'CONTAINER'
and trunc(complete_dstamp) > (
trunc(current_timestamp)-1
)
GROUP BY
trunc(complete_dstamp),
to_char(complete_dstamp, 'HH24'),
user_id
ORDER BY
1,
2
Desired output:
Current output:
Use conditional aggregation:
SELECT TO_CHAR(complete_dstamp, 'YYYY-MM-DD') AS "Date",
user_id AS "User",
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '00' THEN update_qty END) AS hour_0,
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '01' THEN update_qty END) AS hour_1,
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '02' THEN update_qty END) AS hour_2,
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '03' THEN update_qty END) AS hour_3,
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '04' THEN update_qty END) AS hour_4,
-- ...
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '23' THEN update_qty END) AS hour_23,
sum(update_qty) AS grand_total
FROM inventory_transaction
WHERE to_loc_id = 'CONTAINER'
AND complete_dstamp >= trunc(current_timestamp)
GROUP BY
TO_CHAR(complete_dstamp, 'YYYY-MM-DD'),
user_id
ORDER BY
"Date",
"User"
Or a PIVOT:
SELECT "Date",
user_id AS "User",
hour_0,
hour_1,
hour_2,
hour_3,
hour_4,
-- ...
hour_23,
COALESCE(hour_0, 0)
+ COALESCE(hour_1, 0)
+ COALESCE(hour_2, 0)
+ COALESCE(hour_3, 0)
+ COALESCE(hour_4, 0)
-- ...
+ COALESCE(hour_23, 0) AS grand_total
FROM (
SELECT TO_CHAR(complete_dstamp, 'YYYY-MM-DD') AS "Date",
TO_CHAR(complete_dstamp, 'HH24') AS hour,
user_id,
update_qty
FROM inventory_transaction
WHERE to_loc_id = 'CONTAINER'
AND complete_dstamp >= trunc(current_timestamp)
)
PIVOT (
SUM(update_qty) FOR hour IN (
'00' AS hour_0,
'01' AS hour_1,
'02' AS hour_2,
'03' AS hour_3,
'04' AS hour_4,
-- ...
'23' AS hour_23
)
)
db<>fiddle here

Case Expression and dates

I have the below case expression.
SELECT end_dt,
CASE WHEN TO_CHAR(A.END_DT,'MM/DD/YYYY') = '01/01/3000' THEN ''
WHEN TO_CHAR(A.END_DT,'MM/DD/YYYY') > TO_CHAR(SYSDATE,'MM/DD/YYYY') THEN TO_CHAR(SYSDATE,'MM/DD/YYYY')
ELSE TO_CHAR(A.END_DT,'MM/DD/YYYY')
END ENDDATE,
CASE WHEN TO_CHAR(A.END_DT,'YYYYMM') = '300001' THEN ''
WHEN TO_CHAR(A.END_DT,'YYYYMM') > TO_CHAR(SYSDATE,'YYYYMM') THEN TO_CHAR(SYSDATE,'YYYYMM')
ELSE TO_CHAR(A.END_DT,'YYYYMM')
END ENDDATE_YYYYMM,
CASE WHEN TO_CHAR(A.END_DT,'YYYY') = '3000' THEN ''
WHEN TO_CHAR(A.END_DT,'YYYY') > TO_CHAR(SYSDATE,'YYYY') THEN TO_CHAR(SYSDATE,'YYYY')
WHEN TO_CHAR(A.END_DT,'YYYY') > TO_CHAR(SYSDATE,'YYYY') THEN TO_CHAR(SYSDATE,'YYYY')
ELSE TO_CHAR(A.END_DT,'YYYY')
END ENDDATE_YYYY
FROM A
LEFT D ON A.ID = D.ID
WHERE 1=1
ORDER BY 1
OutPut:
End_dt ENDDATE ENDDATE_YYYYMM ENDDATE_YYYY
12/5/2012 14:33:24 01/05/2018 201212 2012
Expected output:
End_dt ENDDATE ENDDATE_YYYYMM ENDDATE_YYYY
12/5/2012 14:33:24 12/5/2012 201212 2012
Why do I get a result of 01/05/2018 and not 12/5/2012?
You're doing string comparisons on dates. Stop. Do date comparisons on dates.
The string '12/5/2012' is greater than the string '01/05/2018' because 1 is greater than 0. Oracle is performing a binary comparison.
SQL> select *
2 from dual
3 where '12/5/2012' > '01/05/2018';
D
-
X
Stop converting all your dates to strings and all will be well
SQL> select *
2 from dual
3 where date '2018-05-01' > date '2012-05-12';
D
-
X
Incidentally, the empty string '' is equivalent to NULL in Oracle.
Your query should look like:
CASE WHEN A.END_DT = date '3000-01-01' then null
WHEN A.END_DT > SYSDATE THEN TO_CHAR(SYSDATE,'MM/DD/YYYY')
ELSE TO_CHAR(A.END_DT,'MM/DD/YYYY')
END ENDDATE,
Don't do date comparisons as strings. It works for the other values, because you have the right format -- YYYYMMDD (or a partial piece of that).
Try this logic:
SELECT end_dt,
(CASE WHEN TO_CHAR(A.END_DT, 'MM/DD/YYYY') = '01/01/3000' THEN ''
WHEN A.END_DT > SYSDATE
THEN TO_CHAR(SYSDATE, 'MM/DD/YYYY')
ELSE TO_CHAR(A.END_DT, 'MM/DD/YYYY')
END) as ENDDATE,
(CASE WHEN TO_CHAR(A.END_DT, 'YYYYMM') = '300001' THEN ''
WHEN TO_CHAR(A.END_DT, 'YYYYMM') > TO_CHAR(SYSDATE, 'YYYYMM')
THEN TO_CHAR(SYSDATE,'YYYYMM')
ELSE TO_CHAR(A.END_DT,'YYYYMM')
END) as ENDDATE_YYYYMM,
(CASE WHEN TO_CHAR(A.END_DT, 'YYYY') = '3000' THEN ''
WHEN TO_CHAR(A.END_DT, 'YYYY') > TO_CHAR(SYSDATE, 'YYYY')
THEN TO_CHAR(SYSDATE, 'YYYY')
WHEN TO_CHAR(A.END_DT, 'YYYY') > TO_CHAR(SYSDATE,'YYYY')
THEN TO_CHAR(SYSDATE, 'YYYY')
ELSE TO_CHAR(A.END_DT, 'YYYY')
END) as ENDDATE_YYYY

Case Statement Questions regarding column names

In the following, I have a case statement. I am wondering if it's possible to have three separate columns in this case statement. Obviously, the 'else end' statement provides the 'Dependents', 'Employees', and 'Spouse' in a 'Relationship' column. I am looking to have 'Employee', 'Spouse', and 'Dependent' to be in their own column.
select
Convert (varchar(6),x.mem_date,112) as IncurMonth,
e.Meme_lev2 as Group#,
e.MEME_GRPN as Groupname,
--MONTH(x.mem_date) AS mem_date,
case when m.mem_rel = '01' then 'Employee'
when m.mem_rel = '02' then 'Spouse'
--when m.MEM_REL = '03' then 'Child'
--when m.MEM_REL = '04' then 'Child/No Financial Resp.'
--when m.MEM_REL = '05' then 'Step child'
--when m.MEM_REL = '06' then 'Foster child'
--when m.MEM_REL = '07' then 'Guardian/POA'
else 'Dependent' end as Relationship,
COUNT(*) as "Members/Subscribers"
from Impact.dbo.tbl_mem m
left join Impact.dbo.tbl_meme e on e.MEME_ID1 = m.MEM_ID1
inner join impactwork.dbo.tbl_mmonth x on x.mem_date between convert(varchar(10), e.meme_eff, 101) and convert(varchar(10), e.meme_trm, 101)
where e.MEME_LEV2 IN ('52032')
and x.mem_date between '01/01/2015' and '03/31/2015'
and meme_rank='900'
group by
e.Meme_lev2,
e.MEME_GRPN,
Convert (varchar(6),x.mem_date,112),
case when m.mem_rel = '01' then 'Employee'
when m.mem_rel = '02' then 'Spouse'
--when m.MEM_REL = '03' then 'Child'
--when m.MEM_REL = '04' then 'Child/No Financial Resp.'
--when m.MEM_REL = '05' then 'Step child'
--when m.MEM_REL = '06' then 'Foster child'
--when m.MEM_REL = '07' then 'Guardian/POA'
else 'Dependent' end
order by group#, Convert (varchar(6),x.mem_date,112), [members/subscribers] desc
IncurMonth Group# Groupname Relationship Members/Subscribers
201501 52005 Rosco LABORATORIES Employee 30
201501 52005 Rosco LABORATORIES Dependent 32
201501 52005 Rosco LABORATORIES Spouse 14
201501 52005 Rosco LABORATORIES RETIREE AR Employee 17
201501 52005 Rosco LABORATORIES RETIREE AR Spouse 6
You can use conditional aggregation to do this. Replace your case statement with an aggregate function with a conditional expression as argument (so that you only count the rows matching the expression).
I used sum below, but you could just as well use count:
count(case when m.mem_rel = '01' then m.mem_rel end) 'Employee',
also remove the expression from the group by clause as you're now using it as an aggregate and should not group by it.
select
Convert(varchar(6),x.mem_date,112) as IncurMonth,
e.Meme_lev2 as Group#,
e.MEME_GRPN as Groupname,
--MONTH(x.mem_date) AS mem_date,
sum(case when m.mem_rel = '01' then 1 else 0 end) 'Employee',
sum(case when m.mem_rel = '02' then 1 else 0 end) 'Spouse',
sum(case when m.MEM_REL NOT IN ('01','02') then 1 else 0 end) 'Dependent',
COUNT(*) as "Members/Subscribers"
from Impact.dbo.tbl_mem m
left join Impact.dbo.tbl_meme e on e.MEME_ID1 = m.MEM_ID1
inner join impactwork.dbo.tbl_mmonth x on x.mem_date between convert(varchar(10), e.meme_eff, 101)
and convert(varchar(10), e.meme_trm, 101)
where e.MEME_LEV2 IN ('52032')
and x.mem_date between '01/01/2015' and '03/31/2015'
and meme_rank='900'
group by
e.Meme_lev2,
e.MEME_GRPN,
Convert(varchar(6),x.mem_date,112)
order by group#, Convert(varchar(6),x.mem_date,112), [members/subscribers] desc;

Oracle SQL Count Records per Hour

So, what I'm trying to do basically is count the amount of shipments, per hour, per carrier, but I'm having difficulties getting it to sum in the columns I want. The goal is to instead of having 1 or 2 under Hour 1 or Hour 2 it would have sum(total shipments). Essentially 24 hours so we could see trends in time of day...
Code:
select router_destination_code,
case when to_char(app_last_updated_date_utc, 'HH24') = '00' then '1' else NULL end as "Hour 1",
case when to_char(app_last_updated_date_utc, 'HH24') = '01' then '2' else NULL end as "Hour 2",
case when to_char(app_last_updated_date_utc, 'HH24') = '02' then '3' else NULL end as "Hour 3",
--case when app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 17:00:00' then count(Router_Destination_code) else NULL end as "Hour_1"
count(Router_Destination_code) as Shipments
from booker.routing_container_history
where
app_last_updated_by_module in ('ManualSlam', 'slam')
and app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 16:00:00'
group by
router_destination_code,
case when to_char(app_last_updated_date_utc, 'HH24') = '00' then '1' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '01' then '2' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '02' then '3' else NULL end
order by
case when to_char(app_last_updated_date_utc, 'HH24') = '00' then '1' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '01' then '2' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '02' then '3' else NULL end,
count(Router_Destination_code) desc;
Output:
But, the Goal is to have the shipments underneath the hour.
Thank you.
Here is a new approach I did.. But it is showing lots of zeros, and would like it only to show numbers the whole way across.
select router_destination_code,
count(case when to_char(app_last_updated_date_utc, 'HH24') = '16' then router_destination_code else NULL end) as "Hour 1",
count(case when to_char(app_last_updated_date_utc, 'HH24') = '17' then router_destination_code else NULL end) as "Hour 2"
--case when app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 17:00:00' then count(Router_Destination_code) else NULL end as "Hour_1"
--count(Router_Destination_code) as Shipments
from booker.routing_container_history
where
app_last_updated_by_module in ('ManualSlam', 'slam')
and app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 16:00:00'
group by
router_destination_code,
case when to_char(app_last_updated_date_utc, 'HH24') = '16' then router_destination_code else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '17' then router_destination_code else NULL end
order by
case when to_char(app_last_updated_date_utc, 'HH24') = '16' then router_destination_code else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '17' then router_destination_code else NULL end,
count(Router_Destination_code) desc;
I do not know if I understood you well but you may try to just extract hour from date and then group by:
Check this fiddle (sorry for bad syntax):
http://sqlfiddle.com/#!4/a0a97/6
create table a (id number, data date);
insert into a (id, data)
values (1, to_date( '2013-01-01 13:12:01', 'yyyy-mm-dd hh24:mi:ss'));
insert into a (id, data)
values (1, to_date( '2013-01-01 13:12:01', 'yyyy-mm-dd hh24:mi:ss'));
insert into a (id, data)
values (1, to_date( '2013-01-01 14:12:01', 'yyyy-mm-dd hh24:mi:ss'));
select to_char(data,'HH24'), count(1) from a group by to_char(data,'HH24');