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

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.

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.

SQL Server query to get data for last two months

SELECT
DAY(table_A.PaymentDate) as date1 ,
(CASE
WHEN MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP)
THEN CAST(SUM(table_A.Total_Amount) As INT)
ELSE 0
END) AS This_month_CNT,
(CASE
WHEN MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP) - 1
THEN CAST(SUM(table_A.Total_Amount) AS INT)
ELSE 0
END) AS last_month_CNT
FROM
Tbl_Pan_Paymentdetails table_A
FULL OUTER JOIN
Tbl_Pan_Paymentdetails table_B ON table_A.PaymentDate = table_B.PaymentDate
WHERE
YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP)
AND table_A.PaymentDate >= DATEADD(MONTH, -2, GETDATE())
GROUP BY
DAY(table_A.PaymentDate),
MONTH(table_A.PaymentDate)
ORDER BY
DAY(table_A.PaymentDate) ;
Not sure I fully understand.
WHERE YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP) AND
table_A.PaymentDate >= DATEADD(MONTH, -2, GETDATE())
Here you are (1) comparing the Year elements of your payment date with CURRENT_TIMESTAMP, and (2) making sure the payment date is greater than the last 2 months based on GETDATE()?
Not sure why you are using both CURRENT_TIMESTAMP and GETDATE(). Either way, I think the second part of that WHERE statement does what you want.
If the current date is January 31, 2015, your currently logic will not return any records from December 2014. The first part of your where statement is filtering them out. If you really want the last 2 months, remove the following from the WHERE statement
YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP) AND

SQL query to get count based differnt condition

Description of table columns -
TYPE : VARCHAR
STATUS : VARCHAR
ORDER_DATE : TIMESTAMP WITH TIMEZONE
Please find the below table structure and required output.
In the required result -
0TO30DAYS : Count of Type for previous 30 days
30TO60DAYS : Count of Type for previous 31 to 60 Days
60TO90DAYS : Count of type for 61 to 90 Days
Please note that I'm using Oracle DB unable to create three different count columns as per the different date range. Please let me know how to create SQL for the same in ORACLE.
count ignores null, so you could count a case expression with your logic:
SELECT type,
COUNT(CASE WHEN day_diff BETWEEN 0 AND 31 THEN 1 ELSE NULL END)
AS "0TO30DAYS",
COUNT(CASE WHEN day_diff BETWEEN 31 AND 61 THEN 1 ELSE NULL END)
AS "30TO60DAYS",
COUNT(CASE WHEN day_diff BETWEEN 61 AND 91 THEN 1 ELSE NULL END)
AS "60TO90DAYS"
FROM (SELECT type, CAST (order_date AS DATE) - SYSDATE AS day_diff
FROM my_table)
GROUP BY type
SELECT TYPE,
CASE
WHEN order_date >= (SYSDATE - 30) AND order_date < SYSDATE THEN
COUNT(TYPE)
END AS count30,
CASE
WHEN order_date >= (SYSDATE - 60) AND order_date < (SYSDATE - 30) THEN
COUNT(TYPE)
END AS count60,
CASE
WHEN order_date >= (SYSDATE - 90) AND order_date < (SYSDATE - 60) THEN
COUNT(TYPE)
END AS count90
FROM TABLE
GROUP BY TYPE, order_date

How to display result in two column form one column resource with different where

I try to count record which is on current date and pass date from date column
DATE
'2013-03-04 00:00:00'
'2013-02-04 00:00:00'
'2013-02-04 00:00:00'
if today is '2013-03-04 00:00:00'
the result should be
CURRENT_DATE = 1
PASS_DATE = 2
I Don't know how to query it form one resource but different where condition
1st - date >= '2013-03-04 00:00:00'
2nd - date < '2013-03-04 00:00:00'
PLEASE HELP
I suggest using two sub-queries within a SELECT clause
select
(select count(*) from MyDates where DateValue < getdate()) as PastDate,
(select count(*) from MyDates where DateValue >= getdate()) as CurrentDate
You can replace getDate() with a date parameter or a hard-coded value such as '2013-03-04' if you wish.
One way to do it is to query for all dates and place 1\0 according to your condition
then just query again from the table an sum the columns.
SELECT sum([CURRENT_DATE]), sum([PASS_DATE])
FROM
(
SELECT
ID,
case when myDate >= getDate() then 1 else 0 end as [CURRENT_DATE],
case when myDate < getDate() then 1 else 0 end as [PASS_DATE]
FROM mytable
) as SourcTbl
Here is a SQL Fiddle http://sqlfiddle.com/#!3/e9c19/8

What is the most efficient way to create an order count summary by hour, day, month in SQL Server 2005?

Given a table:
create table #orders (
orderid int,
orderdatetime datetime
)
What is the best way to write sql to output a report containing the count of orders from the current and previous 24 hours, total orders for the current day and previous 7 days, total orders for the current week and previous 4 weeks, and total orders for the month and previous 6 months?
I'm wondering if this can be efficiently rolled up into a single sql using analytical functions, or if 4 sql statements generating the 4 groups of data is the only (or best) way.
Also, given the hourly/day/week grouping, how would one do that in sql server? Datetimes seem to be a pain in the ass everytime I have to do something like this with them...
Ideas? Put into a SSAS cube and do it from there maybe?
SELECT DATEPART(month, orderdatetime), DATEPART(week, orderdatetime), DATEPART(day, orderdatetime), COUNT(*)
FROM #orders
GROUP BY
DATEPART(month, orderdatetime), DATEPART(week, orderdatetime), DATEPART(day, orderdatetime) WITH ROLLUP
This will group the COUNT's by day, week and month in a single query.
The week rollups will have a NULL in DATEPART(day, orderdatetime) column, the month rollups will have a NULL in both DATEPART(day, orderdatetime) and DATEPART(week, orderdatetime) columns.
To make it for every hour, day, week or month from the current without gaps, use CTE's:
WITH q_hours AS
(
SELECT 0 AS col_hour
UNION ALL
SELECT col_hour + 1
FROM q_hours
WHERE col_hour < 22
),
q_days AS
(
SELECT 0 AS col_day
UNION ALL
SELECT col_day + 1
FROM q_days
WHERE col_day < 31
),
q_months AS
(
SELECT 0 AS col_month
UNION ALL
SELECT col_month + 1
FROM q_months
WHERE col_month < 12
)
SELECT col_month, col_day, col_hour, COUNT(orderid)
FROM q_hours
CROSS JOIN
q_days
CROSS JOIN
q_months
LEFT JOIN
#orders
ON DATEDIFF(month, orderdatetime, GETDATE()) = col_month
AND DATEDIFF(day, orderdatetime, GETDATE()) % 31 = col_day
AND DATEDIFF(hour, orderdatetime, GETDATE()) % 24 = col_hour
GROUP BY
col_month, col_day, col_hour WITH ROLLUP
HAVING (
col_month = 0
AND col_day = 0
AND col_hour IS NOT NULL
) -- all hours within 24 hours from now
OR
(
col_month = 0
AND col_day <= 7
AND col_hour IS NULL
) -- all days within 7 days from now
OR
(
col_month <= 6
AND col_day IS NULL
AND col_hour IS NULL
) -- all months within 6 months from now
You could run the four selects from a "dummy table" or an "identity" table that consists of a single row.
You could have:
SELECT
(<query count of orders current/prev 24 hours>) as <name1>,
(<total orders current + 7 days>) as <name2>,
(<total orders current week + 4 weeks>) as <name3>,
(<total orders month + 6 months>) as <name4>
FROM
<IDENTITY table>;
Because you want different timeframes for each datepart type, using a single query with rollup probably won't give you what you want. I'd consider just unioning them all together similar to something like this...
SELECT DatePartValue = DATEPART(HH, orderdatetime),
Type = 'Hourly',
COUNT(*)
FROM #orders
WHERE orderdatetime > DATEADD(HH, -25, GETDATE())
GROUP BY DATEPART(HH, orderdatetime)
UNION
SELECT DATEPART(DD, orderdatetime),
Type = 'Daily',
COUNT(*)
FROM #orders
WHERE orderdatetime > DATEADD(DD, -8, GETDATE())
GROUP BY DATEPART(DD, orderdatetime)
UNION
SELECT DATEPART(WEEK, orderdatetime),
Type = 'Weekly',
COUNT(*)
FROM #orders
WHERE orderdatetime > DATEADD(WEEK, -5, GETDATE())
GROUP BY DATEPART(WEEK, orderdatetime)
ORDER BY Type, DatePartValue
UNION
SELECT DATEPART(MM, orderdatetime),
Type = 'Monthly',
COUNT(*)
FROM #orders
WHERE orderdatetime > DATEADD(MM, -7, GETDATE())
GROUP BY DATEPART(MM, orderdatetime)
ORDER BY Type, DatePartValue
For results in one row, something like this:
select
orders_day = sum(case when datediff(hour,orderdatetime,getdate()) < 24 then 1 else 0 end)
, orders_week = sum(case when datediff(day,orderdatetime,getdate()) < 7 then 1 else 0 end)
, orders_month = sum(case when datediff(week,orderdatetime,getdate()) < 4 then 1 else 0 end)
, orders_half = sum(case when datediff(month,orderdatetime,getdate()) < 6 then 1 else 0 end)
from #orders
You may want to fine tune the date criteria to get appropriate behavior.
For multiple rows, take the results above and transpose it with UNPIVOT or CASE .. CROSS JOIN.
SELECT
sum(case when orderdatetime between GetDate() - 1 and GetDate() then 1 else 0 end) as Current24Hours,
sum(case when orderdatetime between GetDate() - 2 and GetDate() - 1 then 1 else 0 end) as Previous24Hours,
sum(case when orderdatetime between GetDate() - 7 and GetDate() then 1 else 0 end) as Current7Days,
sum(case when orderdatetime between GetDate() - 14 and GetDate() - 7 then 1 else 0 end) as Previous7Days,
sum(case when DATEDIFF (m, OrderDate, #now) <= 1 then 1 else 0 end) as PreviousMonth,
sum(case when DATEDIFF (m, OrderDate, #now) <= 6 then 1 else 0 end) as PreviousSixMonths
FROM orders
I think you want grouping sets. I've understand that sql server supports grouping sets.
EDIT1: I've read that sql server 2005 doesn't support grouping sets but sql server 2008 does. Here an interesting read on a presumed but not existing difference between mapreduce and an rdbms like Oracle and Sql Server. Please read the comments too!! http://www.data-miners.com/blog/2008/01/mapreduce-and-sql-aggregations.html