Filtering a query with subqueries - sql

In order to understand the question I will explain the result expected.
I have a db table where I save some data of the activity of the current day. Then I want to sum some numeric fields and the last register of the text fields, using a filter between two dates.
Example:
•DB TABLE
ID|CALLS|RESULT | DATE
1 | 2 |FAIL |15/09/16
1 | 1 |ERROR |16/09/16
1 | 3 |OK |17/09/16
•SUM BETWEEN 15 and 17
ID|TOTAL CALLS|LAST RESULT
1 | 6 | OK
•SUM BETWEEN 15 and 16
ID|TOTAL CALLS|LAST RESULT
1 | 3 | ERROR
-Would this be the solution?
SELECT DISTINCT ID,
TOTAL_CALLS=SUM(CALLS),
LAST_RESULT= (
SELECT RESULT FROM TABLE T2 where T2.DATE between MIN(T1.DATE) and MAX (T1.DATE) and T1.ID=T2.ID
)
FROM TABLE T1
WHERE
TIME BETWEEN 15/09/16 and 17/09/16
GROUP BY ID
Thank you very much!
Regards

Use the below query.
;WITH cte_1
AS
(SELECT ID,SUM(CALLS)OVER( PARTITION BY ID) [TOTAL CALLS]
,Result [LAST RESULT]
,ROW_NUMBER()OVER( PARTITION BY ID ORDER BY [DATE] desc) RNO
from #YourTable T
WHERE [DATE] between '09/15/2016' AND '09/16/16')
SELECT ID,[TOTAL CALLS],[LAST RESULT]
FROM cte_1
WHERE Rno=1

You can use TOP 1 WITH TIES with ORDERING to get what you need:
DECLARE #dFrom date = '2016-09-15',
#dTo date = '2016-09-16'
SELECT TOP 1 WITH TIES
ID,
SUM(CALLS) OVER (PARTITION BY ID) [TOTAL CALLS],
RESULT [LAST RESULT]
FROM YourTable
WHERE [DATE] between #dFrom and #dTo
ORDER BY ROW_NUMBER() OVER (PARTITION BY ID ORDER BY [DATE]) DESC

You can use max date to get result column value.
DECLARE #FromDate DATETIME= '15 SEP 2016'
DECLARE #ToDate DATETIME= '16 SEP 2016'
SELECT ID , SUM(CALLS) , ( SELECT RESULT
FROM #yourTable
WHERE [DATE] = #ToDate
) RESULT
FROM **#yourTable**
WHERE [DATE] BETWEEN #FromDate AND #ToDate
GROUP BY ID

Related

Overlapping between first record enddate and next record start date in SQL Server

I have the below kind of data and I need below kind of output.
Input:
id startdate enddate
1 21/01/2019 23/01/2019
1 23/01/2019 24/01/2019
1 24/01/2029 27/01/2019
1 29/01/2019 02/02/2019
Output:
id startdate enddate
1 21/01/2019 27/01/2019
1 29/01/2019 02/02/2019
We need to use the logic of matching the first record enddate and nth record startdate.
This is a gaps-and-islands problem, where you want to group together "adjacent" dates. Here is one approach using window functions: the idea is to compare the current start date to the end date of the "previous" row, and use a window sum to define the groups:
select id, min(startdate) startdate, max(enddate) enddate
from (
select t.*,
sum(case when startdate = lag_enddate then 0 else 1 end) over(partition by id order by startdate) grp
from (
select t.*,
lag(enddate) over(partition by id order by startdate) lag_enddate
from mytable t
) t
) t
group by id, grp
Demo on DB Fiddle - with credits to Sander for creating the DDL statements in the first place:
id | startdate | enddate
-: | :--------- | :---------
1 | 2019-01-21 | 2019-01-27
1 | 2019-01-29 | 2019-02-02
have a look at
NEXT VALUE FOR method, works 2016 and later
Use a CTE or subquery (works in 2008) where you join on your own table using the previous value as a join. Here a sample script I use showing backup growth
declare #backupType char(1)
, #DatabaseName sysname
set #DatabaseName = db_name() --> Name of current database, null for all databaseson server
set #backupType ='D' /* valid options are:
D = Database
I = Database Differential
L = Log
F = File or Filegroup
G = File Differential
P = Partial
Q = Partial Differential
*/
select backup_start_date
, backup_finish_date
, DurationSec
, database_name,backup_size
, PreviouseBackupSize
, backup_size-PreviouseBackupSize as growth
,KbSec= format(KbSec,'N2')
FROM (
select backup_start_date
, backup_finish_date
, datediff(second,backup_start_date,b.backup_finish_date) as DurationSec
, b.database_name
, b.backup_size/1024./1024. as backup_size
,case when datediff(second,backup_start_date,b.backup_finish_date) >0
then ( b.backup_size/1024.)/datediff(second,backup_start_date,b.backup_finish_date)
else 0 end as KbSec
-- , b.compressed_backup_size
, (
select top (1) p.backup_size/1024./1024.
from msdb.dbo.backupset p
where p.database_name = b.database_name
and p.database_backup_lsn< b.database_backup_lsn
and type=#backupType
order by p.database_backup_lsn desc
) as PreviouseBackupSize
from msdb.dbo.backupset as b
where #DatabaseName IS NULL OR database_name =#DatabaseName
and type=#backupType
)as A
order by backup_start_date desc
using a "cursor local fast_forward" to loop over the data on a row-by-row and use a temporary table where you store & compaire prev value
Here is a solution with common table expressions that could work.
Sample data
create table data
(
id int,
startdate date,
enddate date
);
insert into data (id, startdate, enddate) values
(1, '2019-01-21', '2019-01-23'),
(1, '2019-01-23', '2019-01-24'),
(1, '2019-01-24', '2019-01-27'),
(1, '2019-01-29', '2019-02-02');
Solution
-- determine start dates
with cte_start as
(
select s.id,
s.startdate
from data s
where not exists ( select 'x'
from data e
where e.id = s.id
and e.enddate = s.startdate )
),
-- determine date boundaries
cte_startnext as
(
select s.id,
s.startdate,
lead(s.startdate) over (partition by s.id order by s.startdate) as startdate_next
from cte_start s
)
-- determine periods
select sn.id,
sn.startdate,
e.enddate
from cte_startnext sn
cross apply ( select top 1 e.enddate
from data e
where e.id = sn.id
and e.startdate >= sn.startdate
and (e.startdate < sn.startdate_next or sn.startdate_next is null)
order by e.enddate desc ) e
order by sn.id,
sn.startdate;
Result
id startdate enddate
-- ---------- ----------
1 2019-01-21 2019-01-27
1 2019-01-29 2019-02-02
Fiddle to see build up of solution and intermediate CTE results.

Select working days from a calendar in a table

I have a table with a calendar which look like this in SQL Server
Date WorkingDay
20200514 1
20200515 1
20200516 0
20200517 0
20200518 1
20200519 1
20200520 1
20200521 0
20200522 1
I am trying to select the third working day from a specific date.
If I start the 20200514, result must be the 20200518.
I try with a query like this but I do not have the date, only a list of result
select top 3 *
from tmp_workingdays
where workingday = 1 and date >= 20200514
order by date asc
How can I select only the date?
Try the following, here is the demo.
select
date
from
(
select
*,
row_number() over (order by date) as rnk
from tmp_workingdays
where workingday=1
and date >= 20200514
) val
where rnk = 3
output:
| Date |
------------
|2020-05-18|
DECLARE #date AS DATE = '2020-05-14' ;
WITH cte_WorkingDates AS
(
SELECT [Date]
FROM tmp_workingdays
WHERE WorkingDay = 1
)
SELECT [Date]
FROM cte_WorkingDates
WHERE [Date] >= #date
ORDER BY [Date] ASC
OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY ;
select date
from tmp_workingdays
where workingday = 1
and date >= 20200514
order by date asc
OFFSET 2 ROWS
FETCH NEXT 1 ROWS ONLY

Grouping SSRS report on multiple fields

I have a report we will call ReportOne, in this ReportOne I am querying the data for this report with a stored procedure. The stored procedure query returns two values which are 'TravelDate' and 'Status'.
My report has four fields, 'BeginDate', 'EndDate', 'Status', and 'Days'.
My issue is this, I need to group the report by both the 'Status' and consecutive days. Consecutive days coming from TravelDate.
'BeginDate' will be the first new date
'EndDate' will be the last consecutive date.
'Status' will be status.
'Days' will be the number of consecutive days.
Example,
TravelDate | Status
1/1/2001 | Leave
1/2/2001 | Leave
1/3/2001 | Leave
1/5/2001 | Leave
1/6/2001 | Travel
The report will then look as follows.
BeginDate | EndDate | Status | Days
1/1/2001 | 1/3/2001 | Leave | 3
1/5/2001 | 1/5/2001 | Leave | 1
1/6/2001 | 1/6/2001 | Travel | 1
Example
Declare #YourTable Table ([TravelDate] date,[Status] varchar(50))
Insert Into #YourTable Values
('1/1/2001','Leave')
,('1/2/2001','Leave')
,('1/3/2001','Leave')
,('1/5/2001','Leave')
,('1/6/2001','Travel')
Select BeginDate=min(TravelDate)
,EndDate =max(TravelDate)
,Status =max(Status)
,Days =datediff(DAY,min(TravelDate),max(TravelDate))+1
From (
Select *
,Grp = DateDiff(DAY,'1900-01-01',TravelDate) - row_number() over (partition by status order by TravelDate)
From #YourTable
) A
Group By Grp
Order By BeginDate
Returns
BeginDate EndDate Status Days
2001-01-01 2001-01-03 Leave 3
2001-01-05 2001-01-05 Leave 1
2001-01-06 2001-01-06 Travel 1
EDIT -- Capture from Stored Procedure -- #YourTable Structure must match the Structure of Stored Procedure
Declare #YourTable Table ([TravelDate] date,[Status] varchar(50))
Insert Into #YourTable
Exec youStoredProcedure
Select BeginDate=min(TravelDate)
,EndDate =max(TravelDate)
,Status =max(Status)
,Days =datediff(DAY,min(TravelDate),max(TravelDate))+1
From (
Select *
,Grp = DateDiff(DAY,'1900-01-01',TravelDate) - row_number() over (partition by status order by TravelDate)
From #YourTable
) A
Group By Grp
Order By BeginDate
EDIT - Nested Subquery
Select BeginDate=min(TravelDate)
,EndDate =max(TravelDate)
,Status =max(Status)
,Days =datediff(DAY,min(TravelDate),max(TravelDate))+1
From (
Select *
,Grp = DateDiff(DAY,'1900-01-01',TravelDate) - row_number() over (partition by status order by TravelDate)
From (
-- Your Query Here ---
) A
) A
Group By Grp
Order By BeginDate
EDIT - Consumed from a TVF
Select BeginDate=min(TravelDate)
,EndDate =max(TravelDate)
,Status =max(Status)
,Days =datediff(DAY,min(TravelDate),max(TravelDate))+1
From (
Select *
,Grp = DateDiff(DAY,'1900-01-01',TravelDate) - row_number() over (partition by status order by TravelDate)
From [dbo].[YourTableValedFunction](Param1,Param2) src
) A
Group By Grp
Order By BeginDate

Prepare data at ID,Month level in SQL

I have a table that is something like this:
ID Date
1 10/04/2015
1 28/04/2015
1 14/07/2015
1 30/07/2015
1 30/08/2015
2 10/04/2016
2 28/04/2016
2 14/05/2016
2 30/05/2016
but i am trying to achieve like:
ID Date
1 28/04/2015
1 30/07/2015
1 30/08/2015
2 28/04/2016
2 30/05/2016
Could you please help me .
Try this:
select * from (
select id,
[Date],
row_number() over (partition by id, datepart(month, [date]) order by [Date] desc) [rn]
from (
select id,
--date convrsion, 103 - British/French - your style
convert(date, [date], 103) [Date]
from #MyTable
) a
) b where rn = 1
I don't really get the logic of expected result but the query below would work.
SELECT *
FROM yourTable
WHERE DAY([Date])>=28;
See How to get Day, Month and Year Part from DateTime in Sql Server

Select rows where price didn't change

Suppose you have a table like (am using SQL Server 2008, no audit log - table is HUGE):
SecID | Date | Price
1 1/1/11 10
1 1/2/11 10
1 1/3/11 5
1 1/4/11 10
1 1/5/11 10
Suppose this table is HUGE (millions of rows for different secIDs and Date) - I would like to return the records when the price changed (looking for something better than using a cursor and iterating):
Am trying to figure out how to get:
SecID | StartDate | EndDate | Price
1 1/1/11 1/2/11 10
1 1/3/11 1/3/11 5
1 1/4/11 1/5/11 10
i.e. another way to look at it is that I am looking for a range of dates where the price has stayed the same.
This is an "islands" problem.
declare #Yourtable table
(SecID int, Date Date, Price int)
INSERT INTO #Yourtable
SELECT 1,GETDATE()-5,10 union all
SELECT 1,GETDATE()-4,10 union all
SELECT 1,GETDATE()-3,5 union all
SELECT 1,GETDATE()-2,10 union all
SELECT 1,GETDATE()-1, 10
;WITH cte AS
(
SELECT SecID,Date,Price,
ROW_NUMBER() OVER (PARTITION BY SecID ORDER BY Date) -
ROW_NUMBER() OVER (PARTITION BY Price, SecID ORDER BY Date) AS Grp
FROM #Yourtable
)
SELECT SecID,Price, MIN(Date) StartDate, MAX(Date) EndDate
FROM cte
GROUP BY SecID, Grp, Price
ORDER BY SecID, MIN(Date)
If the value does not change, the std deviation will be zero
select secId
from ...
group by secId
having count(*) = 1
OR stdev(price) = 0
I think this should work
SELECT SecID, Min(Date) AS StartDate, Max(Date) AS EndDate, Price FROM BigTable GROUP BY SecID, EndDate Having Min(Date) != MAx(Date) And Date != NULL