sql server select within select - sql

say I have the following query:
select ID, ActualDate, DueDate
from table1
What I need to do is to add another field called Flag
which will be marked as "Y" if ActualDate is greater than DueDate
select ID, ActualDate, DueDate,
CASE
WHEN ActualDate > DueDate THEN 'Y'
ELSE 'N'
END as Flag
from table1
The above won't work as I get invalid column name ActualDate. Invalid column name DueDate.
What I need to do is a select within a select like this:
select ID, ActualDate, DueDate,
CASE
WHEN ActualDate > DueDate THEN 'Y'
ELSE 'N'
END as Flag
from
(select ID, ActualDate, DueDate
from table1) tbl1
)

If your table has the fields in it, then the following should work without the need for a subquery:
select ID,
ActualDate,
DueDate,
CASE
WHEN ActualDate > DueDate
THEN 'Y'
ELSE 'N'
END as Flag
FROM table1
You can use a subquery but it is unnecessary:
select ID,
ActualDate,
DueDate,
CASE
WHEN ActualDate > DueDate
THEN 'Y'
ELSE 'N'
END as Flag
FROM
(
select ID, ActualDate, DueDate
from table1
) tbl1

Related

MSSQL Group by and Select rows from grouping

I'm trying to figure out if what I'm trying to do is possible. Instead of resorting to multiple queries on a table, I wanted to group the records by business date and id then group by the id and select one date for a field and another date for the other field.
SELECT
*
{AMOUNT FROM DATE}
{AMOUNT FROM OTHER DATE}
FROM (
SELECT
date,
id,
SUM(amount) AS amount
FROM
table
GROUP BY id, date
AS subquery
GROUP BY id
It seems that you're looking to do a pivot query. I usually use cross tabs for this. Based on the query you posted, it could look like:
SELECT
id,
SUM(CASE WHEN date = '20190901' THEN amount ELSE 0 END) AmountFromSept01,
SUM(CASE WHEN date = '20191001' THEN amount ELSE 0 END) AmountFromOct01
FROM (
SELECT
date,
id,
SUM(amount) AS amount
FROM
table
GROUP BY id, date
)AS subquery
GROUP BY id;
You could also use a CTE.
WITH CTE AS(
SELECT
date,
id,
SUM(amount) AS amount
FROM
table
GROUP BY id, date
)
SELECT
id,
SUM(CASE WHEN date = '20190901' THEN amount ELSE 0 END) AmountFromSept01,
SUM(CASE WHEN date = '20191001' THEN amount ELSE 0 END) AmountFromOct01
FROM CTE
GROUP BY id;
Or even be a rebel and do the operation directly.
SELECT
id,
SUM(CASE WHEN date = '20190901' THEN amount ELSE 0 END) AmountFromSept01,
SUM(CASE WHEN date = '20191001' THEN amount ELSE 0 END) AmountFromOct01
FROM CTE
GROUP BY id;
However, some people have tested for performance and found that pre-aggregating can improve performance.
If I understand you correctly, then you're just trying to pivot, but only with two particular dates:
select id,
date1 = sum(iif(date = '2000-01-01', amount, null)),
date2 = sum(iif(date = '2000-01-02', amount, null))
from [table]
group by id

How to use "union all" in SQL?

I have two queries.
The first:
SELECT CreatedOn, COUNT(*) AS locationNonProcessed
FROM Table1
WHERE IsActive = 0
GROUP BY CAST(CreatedOn AS DATE), CreatedOn
The second:
SELECT CreatedOn, COUNT(*) AS locationProcessed
FROM Table1
WHERE IsActive = 1
GROUP BY CAST(CreatedOn AS DATE), CreatedOn
How should I use UNION ALL with these queries?
I don't think you really want union all. That is trivial to implement and results in not very sensible results (you won't know which count is which).
I suspect you want conditional aggregation:
SELECT CAST(CreatedOn AS DATE),
SUM(CASE WHEN IsActive = 0 THEN 1 ELSE 0 END) AS locationNonProcessed,
SUM(CASE WHEN IsActive = 1 THEN 1 ELSE 0 END) as locationProcessed
FROM Table1
GROUP BY CAST(CreatedOn AS DATE);
Note the fix to the SELECT and GROUP BY.
If IsActive takes on only the values of 0, 1, and possibly NULL, this can be simplified to:
SELECT CAST(CreatedOn AS DATE),
SUM(1 - IsActive) AS locationNonProcessed,
SUM(IsActive) as locationProcessed
FROM Table1
GROUP BY CAST(CreatedOn AS DATE);
SELECT createdon, IsActive, COUNT(*) AS locationProcessed
FROM Table1
WHERE IsActive in (0, 1)
GROUP BY CAST(CreatedOn AS DATE), CreatedOn, IsActive
GROUP BY CAST(CreatedOn AS DATE), CreatedOn is odd to me. That is not different than GROUP BY CreatedOn.
SELECT createdon,
SUM(CASE WHEN IsActive = 0 THEN 1 ELSE 0 END) AS locationNonProcessed,
SUM(CASE WHEN IsActive = 1 THEN 1 ELSE 0 END) as locationProcessed
FROM Table1
GROUP BY CAST(CreatedOn AS DATE), CreatedOn;

sql join and group by generated date range

I have Table1 and I need a query to populate Table2:
Problem here is with Date column. I want to know the process of location/partner combination per day. Main issue here is that I can't pick DateCreated and make it as default date since it doesn't necessarily cover whole date range, like in this example where it doesn't have 2015-01-07 and 2015-01-09. Same case with other dates.
So, my idea is to first select dates from some table which contains needed date range and then perform calculation for each day/location/partner combination from cte but in that case I can't figure out how to make a join for LocationId and PartnerId.
Columns:
Date - CreatedItems - number of created items where Table1.DateCreated = Table2.Date
DeliveredItems - number of delivered items where Table1.DateDateOut = Table2.Date
CycleTime - number of days delivered item was in the location (DateOut - DateIn + 1)
I started with something like this but it's very like that I completely missed the point with it:
with d as
(
select date from DimDate
where date between DATEADD(DAY, -365, getdate()) and getdate()
),
cr as -- created items
(
select
DateCreated,
LocationId,
PartnerId,
CreatedItems = count(*)
from Table1
where DateCreated is not null
group by DateCreated,
LocationId,
PartnerId
),
del as -- delivered items
(
select
DateOut,
LocationId,
ParnerId,
DeliveredItems = count(*),
CycleTime = DATEDIFF(Day, DateOut, DateIn)
from Table1
where DateOut is not null
and Datein is not null
group by DateOut,
LocationId,
PartnerId
)
select
d.Date
from d
LEFT OUTER JOIN cr on cr.DateCreated = d.Date -- MISSING JOIN PER LocationId and PartnerId
LEFT OUTER JOIN del on del.DateCompleted = d.Date -- MISSING JOIN PER LocationId and PartnerId
with range(days) as (
select 0 union all select 1 union all select 2 union all
select 3 union all select 4 union all select 5 union all
select 6 /* extend as necessary */
)
select dateadd(day, r.days, t.DateCreated) as "Date", locationId, PartnerId,
sum(
case
when dateadd(day, r.days, t.DateCreated) = t.DateCreated
then 1 else 0
end) as CreatedItems,
sum(
case
when dateadd(day, r.days, t.DateCreated) = t.Dateout
then 1 else 0
end) as DeliveredItems,
sum(
case
when dateadd(day, r.days, t.DateCreated) = t.Dateout
then datediff(days, t.DateIn, t.DateOut) + 1 else 0
end) as CycleTime
from
<yourtable> as t
inner join range as r
on r.days between 0 and datediff(day, t.DateCreated, t.DateOut)
group by dateadd(day, r.days, t.DateCreated), LocationId, PartnerId;
If you only want the end dates (rather than all the dates in between) this is probably a better approach:
with range(dt) as (
select distinct DateCreated from T union
select distinct DateOut from T
)
select r.dt as "Date", locationId, PartnerId,
sum(
case
when r.dt = t.DateCreated
then 1 else 0
end) as CreatedItems,
sum(
case
when r.dt = t.Dateout
then 1 else 0
end) as DeliveredItems,
sum(
case
when r.dt = t.Dateout
then datediff(days, t.DateIn, t.DateOut) + 1 else 0
end) as CycleTime
from
<yourtable> as t
inner join range as r
on r.dt in (t.DateCreated, t.DateOut)
group by r.dt, LocationId, PartnerId;
If to specify WHERE clause? Something Like that:
WHERE cr.LocationId = del.LocationId AND
cr.PartnerId = del.PartnerId

Multiple sub queries

Is it possible to get the result as below from the same table date-wise records:
Enrolled Enrolled as Email Enrolled as Text Deals Redeemed
<First Date> 7 5 2 6
<Next Date> 9 3 6 14
Table structure look something like this:
Customer_id, field1, field2, responsecode, created_date
My current query is something like this:
Select
Created,
Enroll = (Select COUNT(*) from tblCustomer where field1 <> '' group by created),
Email = (Select COUNT(field1) from tblCustomer where field1 = 'E-mail' and field1 <> '' group by created),
Cell = (Select COUNT(*) from tblCustomer where field1 = 'Cell Phone' and field1 <> '' group by created)
from tblCustomer
group by created
order by created
You don't want a COUNT(), but instead, a SUM( CASE/WHEN )
Select
Created,
count(*) TotalCnt,
SUM( CASE WHEN Field1 = 'E-mail' then 1 else 0 END ) as EMailCnt,
SUM( CASE WHEN Field1 = 'Cell Phone' then 1 else 0 END ) as CellCnt,
SUM( CASE WHEN RedeamedCondition then 1 else 0 END ) as RedeamCnt
from
tblCustomer
group by
created
order by
created
Note... if created is a date/time you will need to have the group by based on the date portion ONLY of the "created", otherwise you would get different counts for every second... From another post, the following gets only the date portion of a date time by basically removing the hours:minutes:seconds portion
DATEADD(dd, 0, DATEDIFF(dd, 0, created))
or if that doesn't make sense, you could just do it by
datepart( yy, created) as GrpYear,
datepart( mm, created) as GrpMonth,
datepart( dd, created) as GrpDay, ... rest of columns.....
Try:
select created_date,
count(field1) Enrolled,
count(case field1 when 'E-mail' then 1 end) Enrolled_as_Email,
count(case field1 when 'Cell Phone' then 1 end) Enrolled_as_Cell,
(Select COUNT(*)
from tbl_TransactionDishout d
where d.created = c.created_date and
d.DishoutResponseCode = '0000') Deals_Redeemed
from tblCustomer c
group by created_date
order by created_date

t-sql include column if condition exists

If I have an sql statement:
select call_id, title, description, due_date
from calls
I want to include a column if the condition due_date < getdate() is true.
I was thinking this column would be of type bit, and be set to 1 if condition is true and 0 if condition is false.
Know how I can do this?
select
call_id,
title,
description,
due_date,
case when due_date < getdate() then 1 else 0 end
from calls
SELECT call_id, title, description, due_date,
CASE WHEN due_date < getdate() THEN CAST(1 AS BIT) ELSE 0 END overdue
FROM calls