Multiple Counts from the same row with range - sql

I am trying to get number of transactions within the week given start date and end date.The below query works fine for one day 2011-10-14
SELECT COUNT(operationId) AS trans
FROM hwfg_t_Tracking
WHERE hitTime BETWEEN '2011-10-14 00:00:00' AND '2011-10-14 23:59:59.99'
GO
How can I get the count on operationId where hitTime between 14,13,12,11,10,9,8(1 week) with the single SELECT statement. Like number of transactions for 2011-10-14 as a column, 2011-10-13 as another column and so on

Try the following query for one row per day in your specified range:
SELECT cast(hitTime AS date) AS mydate, COUNT(operationId) AS trans
FROM hwfg_t_Tracking
WHERE hitTime >= '2011-10-14 00:00:00' AND hitTime < '2011-10-21 00:00:00'
GROUP BY cast(hitTime AS date)
Or, if you want them all in one row:
SELECT COUNT(*) AS total_sum
,COUNT(CASE WHEN cast(dt As date) = '2011-10-14' THEN 1 ELSE NULL END) AS day14
,COUNT(CASE WHEN cast(dt As date) = '2011-10-15' THEN 1 ELSE NULL END) AS day15
,COUNT(CASE WHEN cast(dt As date) = '2011-10-16' THEN 1 ELSE NULL END) AS day16
-- etc.
FROM hwfg_t_Tracking
WHERE hitTime >= '2011-10-14 00:00:00' AND hitTime < '2011-10-21 00:00:00'

Related

How to get count of a column between a certain date range without changing the Where clause in SQL

I have a table that has account number, group category and date.
I have a query that does this
Select count(AccNum)
FROM Table
Where date BETWEEN '2020-02-01' AND '2020-03-31'
AND
group IN ('groupA','groupB')
Now is there any way for me to make it work like this
Select count(AccNum) Where date between 2020-02-01 AND '2020-02-31' AS CountFebuary, count(AccNum) Where date between 2020-03-01 AND '2020-02-31' AS CountMarch,
FROM Table
Where date BETWEEN '2020-02-01' AND '2020-03-31'
AND
group IN ('groupA','groupB')
I want to be able to get the total count of accounts for each month without writing a separate query for it. Is that possible?
You can do conditional aggregation:
select
sum(case when date >= '2020-02-01' and date < '2020-03-01' then 1 else 0 end) cnt_february,
sum(case when date >= '2020-03-01' and date < '2020-04-01' then 1 else 0 end) cnt_march
from mytable
where
date >= '2020-02-01' and date < '2020-04-01'
and group IN ('groupA','groupB')
Since you only want two months of data, then we can shorten the conditional expressions a little:
select
sum(case when date < '2020-03-01' then 1 else 0 end) cnt_february,
sum(case when date >= '2020-03-01' then 1 else 0 end) cnt_march
from mytable
where
date >= '2020-02-01' and date < '2020-04-01'
and group IN ('groupA','groupB')
If you are running MySQL, we can shorten some more:
select
sum(date < '2020-03-01') cnt_february,
sum(date >= '2020-03-01') cnt_march
from mytable
where
date >= '2020-02-01' and date < '2020-04-01'
and group IN ('groupA','groupB')
Side note: group is a reserved word in most databases, hence not a good choice for a column name.

Changing multiple select query into CTE query

I want to change this particular simple select query into CTE in order to optimize it, as this simple three select query taking 4 mins and so, I want to reduce the execution time of it by converting it into CTE query.
select sum(AMOUNT) usd from data where status IN ('ACCEPTED','REJECTED','CANCELLED') and date between '01-SEP-18' and '30-NOV-18'
UNION
select sum(AMOUNT) usd from data where status IN ('ACCEPTED','REJECTED','CANCELLED') and date between '01-NOV-18' and '31-JAN-19'
UNION
select sum(AMOUNT) usd from data where status IN ('ACCEPTED','REJECTED','CANCELLED') and date between '01-FEB-19' and '30-APR-19'
ORDER BY usd DESC ;
The expected result should be one column showing the result of the three queries, which is the sum as usd of the amount in this query.
Example:
USD
100 (timeline 1)
200 (timeline 2)
300 (timeline 3)
The one I tried:
Can you conver this CTE query with sum instead of count.
WITH cte AS (
SELECT
COUNT(CASE WHEN status_date BETWEEN '2018-11-01' AND '2019-01-31' THEN 1 END) AS cnt1,
COUNT(CASE WHEN status_date BETWEEN '2019-02-01' AND '2019-04-30' THEN 1 END) AS cnt2,
COUNT(CASE WHEN status_date BETWEEN '2019-05-01' AND '2019-07-31' THEN 1 END) AS cnt3
FROM data
WHERE status IN ('ACCEPTED', 'REJECTED', 'CANCELLED')
)
SELECT cnt1 FROM cte
UNION ALL
SELECT cnt2 FROM cte
UNION ALL
SELECT cnt3 FROM cte;
I am guessing that you don't want the timelines to overlap, so:
select (case when date between '01-SEP-18' and '30-NOV-18' then 'timeline1'
when date between '01-DEC-18' and '31-JAN-19' then 'timeline2'
when date between '01-FEB-19' and '30-APR-19' then 'timeline3'
end), sum(AMOUNT) as usd
from data
where status IN ('ACCEPTED','REJECTED','CANCELLED') and
date between '01-SEP-18' and '30-APR-19'
group by (case when date between '01-SEP-18' and '30-NOV-18' then 'timeline1'
when date between '01-DEC-18' and '31-JAN-19' then 'timeline2'
when date between '01-FEB-19' and '30-APR-19' then 'timeline3'
end)
order by usd desc;
If you do, separate columns are probably simpler:
select sum(case when date >= date '2018-09-01' and date < date '2018-12-01' then amount end) as usd_timeline1,
sum(case when date >= date '2018-11-01' and date < date '2019-02-01' then amount end) as usd_timeline2
sum(case when date >= date '2019-02-01' and date '2019-05-01' then amount end) as usd_timeline3
from data
where status IN ('ACCEPTED','REJECTED','CANCELLED') and
date >= date '2018-09-01' and date < date '2019-05-01'
order by usd desc;
Note that this uses date constants using the ISO standard YYYY-MM-DD format and the date keyword.

Aggregating table values by dates in table [SQL]

I have a table with cust_id, sku, date, order_number (if it's that customer's 1st, 2nd...) and amount. My end goal is to find the total spent by each customer during their first year (exact dates will be relative to each customer).
The sales data table is rld_sales with the following columns:
cust_id
sku,
date of purchase,
order number (if it's that customer's 1st or 2nd...)
-- CREATES TABLE OF CUSTOMER_ID AND Y1, Y2 [END DATES]
CREATE TABLE customer_timetable AS (SELECT
rld_sales. "customer_id" AS cust_id,
CAST(date(rld_sales."date") + INTERVAL '1 year' AS DATE) as y1,
CAST(date(rld_sales."date") + INTERVAL '2 year' AS DATE) as y2
FROM
rld_sales
WHERE
transaction_order = 1
GROUP BY
rld_sales. "customer_id",
date
);
-- JOINS CUSTOMER_TIMETABLE WITH RLD_SALES
CREATE TABLE t1 AS (
SELECT
customer_timetable.cust_id,
customer_timetable.y1,
customer_timetable.y2,
rld_sales.*
FROM
customer_timetable
JOIN rld_sales ON (customer_timetable.cust_id = rld_sales.customer_id)
);
SELECT
t1. "cust_id",
SUM(t1. "amount"),
SUM(t2. "amount")
FROM
t1
WHERE
CAST(date AS DATE) BETWEEN y1
AND y2
LEFT JOIN (
SELECT
t1. "amount"
FROM
t1
WHERE
CAST(date AS DATE) > t1. "y2") t2 ON t1. "cust_id" = t2. "cust_id"
GROUP BY
t1. "cust_id"
SELECT
*
FROM
customer_timetable;
So far I've had minimal success creating intermediate tables and joining one at a time, but I feel like there has to be a much more elegant way to make it all happen in a single query.
If I guess you are using MySQL database, This following query will give you some guideline of writing standard SQL to achieve your requirement-
SELECT
A.customer_id,
CASE
WHEN A."date" >= DATE_ADD(CAST(NOW() AS DATE), INTERVAL -1 YEAR) THEN 'Last_Year'
WHEN A."date" >= DATE_ADD(CAST(NOW() AS DATE), INTERVAL -2 YEAR) THEN 'Last_Previous_Year'
ELSE 'Before_That'
END 'Year',
SUM(amount) -- Not sure your amount in which table. Add Table Alias before the coulmn name if required
FROM rld_sales A
INNER JOIN customer_timetable B ON A.customer_id = B.cust_id
GROUP BY
A.customer_id,
CASE
WHEN A."date" >= DATE_ADD(CAST(NOW() AS DATE), INTERVAL -1 YEAR) THEN 'Last_Year'
WHEN A."date" >= DATE_ADD(CAST(NOW() AS DATE), INTERVAL -2 YEAR) THEN 'Last_Previous_Year'
ELSE 'Before_That'
END
To get yearly values per column ID wise, use this following query-
SELECT A.customer_id,
SUM(CASE WHEN A."Year" = 'Last_Year' THEN Amount ELSE 0 END) 'Last_Year',
SUM(CASE WHEN A."Year" = 'Last_Previous_Year' THEN Amount ELSE 0 END) 'Last_Previous_Year',
SUM(CASE WHEN A."Year" = 'Before_That' THEN Amount ELSE 0 END) 'Before_That'
FROM
(
SELECT
A.customer_id,
CASE
WHEN A."date" >= DATE_ADD(CAST(NOW() AS DATE), INTERVAL -1 YEAR) THEN 'Last_Year'
WHEN A."date" >= DATE_ADD(CAST(NOW() AS DATE), INTERVAL -2 YEAR) THEN 'Last_Previous_Year'
ELSE 'Before_That'
END 'Year',
SUM(amount) Amount -- Not sure your amount in which table. Add Table Alias before the coulmn name if required
FROM rld_sales A
INNER JOIN customer_timetable B ON A.customer_id = B.cust_id
GROUP BY
A.customer_id,
CASE
WHEN A."date" >= DATE_ADD(CAST(NOW() AS DATE), INTERVAL -1 YEAR) THEN 'Last_Year'
WHEN A."date" >= DATE_ADD(CAST(NOW() AS DATE), INTERVAL -2 YEAR) THEN 'Last_Previous_Year'
ELSE 'Before_That'
END
)A
GROUP BY A.customer_id
I would write this as:
select s.customer_id, sum(s.amount)
from rld_sales s
where s.date < (select min(s2.date) + interval 1 year
from rld_sales s2
where s2.customer_id = s.customer_id
)
group by s.customer_id;
Temporary tables would only seem to make this query more complicated.

Summing Moving Range and Criteria, Grouping by Day

What I'm trying to do is sum the last 30 days based on criteria and group by the day, one day of code looks like this:
select
sum(case when f.hire_date__c between '2017-08-01 00:00:00' and '2017-09-01
00:00:00'
and t.createddate between '2017-08-01 00:00:00' and '2017-09-01 00:00:00'
and t.name = 'Request' then 1 else 0 end) as Requests
from case_task_c as t
join case_file_c as f
on f.id = t.case_file__c
I could adjust dates accordingly for the 30 day look back based on today's date, etc. What I can't figure out is to have this query group by day for each day, i.e, yesterdays results, the day prior, etc for the adjusted date ranges.
So far I have this:
select
date(cast(f.hire_date__c as date)),
row_number() over (order by f.hire_date__c desc) as rownumber,
rr.Cancels as Cancels,
qq.hires as hires,
sum(rr.Cancels) over (rows between 1 following and 30 following) as
CumulCancel,
sum(qq.Hires) over (rows between 1 following and 30 following) as Hires
from case_file_c as f
left join(
select
cast(f.hire_date__c as date) as date1,
sum(case when
t.name = 'Cancellation Request' then 1 else 0 end) as Cancels
from case_task_c as t
join case_file_c as f
on f.id = t.case_file__c
group by date1)
as rr
on rr.date1 = cast(f.hire_date__c as date)
left join(
select
cast(f.hire_date__c as date) as date2,
sum(case when f.hire_date__c is not null then 1 else 0 end) as
hires
from sf_case_file_c as f
group by date2) as qq
on qq.date2 = cast(f.hire_date__c as date)
where f.hire_date__c is not null
and f.hire_date__c >= '2017-01-01 00:00:00'
and f.hire_date__c between date_add('day',-30,current_date) and current_date
group by f.hire_date__c, rr.Cancels, qq.hires
order by f.hire_date__c desc
Even using 'current_date - interval -30 day' is just looking up.. the current date.
Using Postgres 8.0.2
Use group by like following. You are converting datetime to date in column selection but not in group by
GROUP BY date(cast(f.hire_date__c as date)),rr.Cancels, qq.hires

SQL Server - Dividing one column by another in a SELECT query

I am seeking to make some Week On Week comparisons in a SELECT query.
The basic code will select distinct areas in the leftmost column, then the following code:
SELECT
(CASE WHEN TIMESTAMP >= GETDATE() -7 AND TIMESTAMP < GETDATE()
THEN ORDER_ID
ELSE NULL
END) AS THISWEEK
SELECT
(CASE WHEN TIMESTAMP >= GETDATE() -14 AND TIMESTAMP < GETDATE() -7
THEN ORDER_ID
ELSE NULL
END) AS LASTWEEK
I'd really like to be able to have (THISWEEK / LASTWEEK) - 1 (Like I would in excel)
Is this possible?
Is this what you want?
select (thisweek / lastweek) - 1
from (SELECT (CASE WHEN TIMESTAMP >= GETDATE() -7 AND TIMESTAMP < GETDATE()
THEN ORDER_ID
END) AS THISWEEK,
(CASE WHEN TIMESTAMP >= GETDATE() -14 AND TIMESTAMP < GETDATE() -7
THEN ORDER_ID
END) AS LASTWEEK
from . . .
) t
It defines the variables in a subquery and then ues them. Note that there is not any performance penalty for this; SQL Server does not "instantiate" the subquery.