SQL Row Order based on Columns - sql

I am trying to implement an order column based on THREADPK1 and Date columns in my query.
Example Results (with desired column on end called date_position :
ThreadSourceKey CourseNumber Date ReadCount Date Position
1518055 0701117023LFC 2016-08-24 18 1
1522610 0701117023LFC 2016-08-24 2 1
5443433 0701117023LFC 2016-08-25 1 1
5443433 0701117023LFC 2016-08-27 1 2
5443344 0701117023LFC 2016-08-21 1 1
5443344 0701117023LFC 2016-08-20 1 2
This is my query: Interested to know how to incorporate the ordering of Date position.
SELECT DISTINCT rs.threadsourcekey,
dc.coursenumber,
CONVERT (DATE, rs.modifieddate, 103) AS 'Date',
Sum(rs.recentreadcount) AS ReadCount
FROM customfinal.rsreportingfactforumreadcounts rs
INNER JOIN #threads threads
ON rs.threadsourcekey = threads.threadsourcekey
INNER JOIN final.dimcourse dc
ON rs.coursekey = dc.coursekey
WHERE rs.coursekey = #CourseKey
AND rs.modifieddate >= Dateadd(day, -7, #DefaultDate)
AND rs.usersourcekey >- 1
AND rs.recentreadcount <> 0
GROUP BY rs.threadsourcekey,
dc.coursenumber,
CONVERT (DATE, rs.modifieddate, 103)

select
ThreadSourceKey,
CourseNumber,
[Date],
ReadCount,
Date_Position = row_number() over (partition by ThreadSourceKey order by [Date])
from
(your sql statement) a

Assuming your query works fine, adding ROW_NUMBER() should get you what you want.
Note that since your GROUP BY has CONVERT (DATE, rs.modifieddate, 103) you need to use exactly that to partition by.
SELECT DISTINCT rs.threadsourcekey,
dc.coursenumber,
CONVERT (DATE, rs.modifieddate, 103) AS 'Date',
Sum(rs.recentreadcount) AS ReadCount,
ROW_NUMBER() OVER (partition by rs.threadsourcekey order by CONVERT (DATE, rs.modifieddate, 103)) AS [DATE POSITION]
FROM customfinal.rsreportingfactforumreadcounts rs
INNER JOIN #threads threads
ON rs.threadsourcekey = threads.threadsourcekey
INNER JOIN final.dimcourse dc
ON rs.coursekey = dc.coursekey
WHERE rs.coursekey = #CourseKey
AND rs.modifieddate >= Dateadd(day, -7, #DefaultDate)
AND rs.usersourcekey >- 1
AND rs.recentreadcount <> 0
GROUP BY rs.threadsourcekey,
dc.coursenumber,
CONVERT (DATE, rs.modifieddate, 103)
Here is a snippet if you want to pick at and see how it works.
SELECT threadsourcekey,
ModDate AS 'Date',
Sum(ReadCount) AS ReadCount ,
ROW_NUMBER() OVER (partition by threadsourcekey order by ModDate) AS [DATE POSITION]
FROM
( VALUES
(1518055, '2016-08-24', 1),
(1518055, '2016-08-24', 1),
(1518055, '2016-08-24', 1),
(1522610, '2016-08-24', 1),
(1522610, '2016-08-24', 1),
(5443433, '2016-08-25', 1),
(5443433, '2016-08-27', 1),
(5443344, '2016-08-21', 1),
(5443344, '2016-08-20', 1)
) As Tbl (ThreadSourceKey, ModDate, ReadCount)
GROUP BY threadsourcekey,
ModDate

Related

fetch two distinct rows with discontinued dates

I want to fetch two rows with discontinued dates from a data sample ex: end date of 1st row should be equal to start date of next row and I want to print whole two rows
tried lead but it did not work
select t1.*
from (select t.*, lead(cast(startdate as date)) over (order by currenykey,cast(enddate as date)) as next_start_date
from table t
) t1
where enddate <> next_start_date
start date end date
1 11/6/17 0:00.00 11/13/17 0:00.00
2 11/13/17 0:00.00 12/26/17 0:00.00
3 12/26/17 0:00.00 1/8/18 0:00.00
4 10/22/18 0:11.13 2/25/19 0:16.35
5 2/25/19 0:16.35 3/4/19 0:09.57
6 3/4/19 0:09.57 3/11/19 0:12.30
7 3/11/19 0:12.30 3/18/19 0:10.21
8 3/18/19 0:10.21 3/25/19 0:09.20
9 3/25/19 0:09.20 4/1/19 0:10.19
I want o print entire rows 3 and 4
If you're on SQL Server 2012 or later you could use the LAG and LEAD functions:
LAG (Transact-SQL)
LEAD (Transact-SQL)
For example...
declare #StackOverflow table (
[ID] int not null,
[StartDate] datetime not null,
[EndDate] datetime not null
);
insert #StackOverflow values
(1, '11/6/17 0:00.00', '11/13/17 0:00.00'),
(2, '11/13/17 0:00.00', '12/26/17 0:00.00'),
(3, '12/26/17 0:00.00', '1/8/18 0:00.00'),
(4, '10/22/18 0:11.13', '2/25/19 0:16.35'),
(5, '2/25/19 0:16.35', '3/4/19 0:09.57'),
(6, '3/4/19 0:09.57', '3/11/19 0:12.30'),
(7, '3/11/19 0:12.30', '3/18/19 0:10.21'),
(8, '3/18/19 0:10.21', '3/25/19 0:09.20'),
(9, '3/25/19 0:09.20', '4/1/19 0:10.19');
select [ID], [StartDate], [EndDate]
from (
select [ID],
[StartDate],
[EndDate],
[Previous] = cast(lag([EndDate]) over (order by [ID]) as date),
[Next] = cast(lead([StartDate]) over (order by [ID]) as date)
from #StackOverflow SO
) SO
where Previous != cast([StartDate] as date)
or Next != cast([EndDate] as date);
Which yields:
ID StartDate EndDate
3 26/12/2017 00:00:00 08/01/2018 00:00:00
4 22/10/2018 00:11:00 25/02/2019 00:16:00
Your query is on the right path, with two caveats:
You want to convert to dates for the comparison.
You need to compare both lead() and lag().
So:
select t.*
from (select t.*,
lead(startdate) over (order by startdate) as next_startdate,
lag(enddate) over (order by startdate) as prev_enddate
from t
) t
where convert(date, enddate) <> convert(date, next_startdate) or
convert(date, startdate) <> convert(date, prev_enddate) ;
That said, I think you are safer with not exists subqueries:
select *
from t
where (not exists (select 1
from t t2
where convert(date, t.startdate) = convert(date, t2.enddate)
) or
not exists (select 1
from t t2
where convert(date, t.enddate) = convert(date, t2.startdate)
)
) and
t.startdate <> (select min(t2.startdate) from t t2) and
t.startdate <> (select max(t2.startdate) from t t2) ;
Here is a db<>fiddle.
To understand why, consider what happens if the start date of line 3 changes. Here is an example where the two do not produce the same results.

Get the aggregated result of a GROUP BY for each value on WHERE clause in TSQL

I have a table in SQL Server with the following format
MType (Integer), MDate (Datetime), Status (SmallInt)
1, 10-05-2018, 1
1, 15-05-2018, 1
2, 25-3-2018, 0
3, 12-01-2018, 1
....
I want to get the MIN MDate for specific MTypes for future dates. In case there isn't one, then the MType should be returned but with NULL value.
Here is what I have done until now:
SELECT m.MType,
MIN(m.MDate)
FROM MyTypes m
WHERE m.MType IN ( 1, 2, 3, 4)
AND m.MDate > GETDATE()
AND m.Status = 1
GROUP BY m.MType
Obviously, the above will return only the following:
1, 10-05-2018
Since there are any other rows with future date and status equals to 1.
However, the results I want are:
1, 10-05-2018
2, NULL
3, NULL
4, NULL //this is missing in general from the table. No MType with value 4
The table is big, so performance is something to take into account. Any ideas how to proceed?
One way is to join the table to itself and filter the date in the ON clause.
SELECT a.Mtype, MIN(b.MDate)
FROM MyTypes a
LEFT JOIN MyTypes b
ON a.MType = b.MType
AND b.MDate > GETDATE()
AND b.Status = 1
WHERE a.MType IN ( 1, 2, 3)
GROUP BY a.MType
Here's a Demo.
I don't know what is logic behind but it seems to use of look-up tables
SELECT a.MType, l.MDate
FROM
(
values (1),(2),(3),(4)
)a (MType)
LEFT JOIN (
SELECT m.MType,
MIN(m.MDate) MDate
FROM MyTypes m
WHERE m.MDate > GETDATE()
AND m.Status = 1
GROUP BY m.MType
)l on l.MType = a.MType
Use a windows function and a union to a numbers table:
declare #t table (MType int, MDate datetime, [Status] smallint)
Insert into #t values (1, convert(date, '10-05-2018', 103), 1)
,(1, convert(date, '15-05-2018', 103), 1)
,(2, convert(date, '25-03-2018', 103), 0)
,(3, convert(date, '12-01-2018', 103), 1)
Select DISTINCT Mtype
, min(iiF(MDate>getdate() and status = 1, MDate, NUll)) over (Partition By Mtype) as MDate
from ( SELECT TOP 10000 row_number() over(order by t1.number) as MType
, '1900-01-01' as MDate, 0 as [Status]
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
union
Select Mtype, MDate, [Status] from #t
) x
where MType in (1,2,3,4)
order by x.MType

Creating a Month Bucket from Query Result

I have the following query result:
But I want to group the results by number, and categorize the quantity by month, so the resulting output would be:
How can I create a month bucket to pick up the date and make it a column and place the values accordingly. Here is my attempt so far:
select converT(varchar,year(NewShipDate)) + 'M' + MonthBucket,
*
from(
select ItemNumber, des.[Product Family], ItemDescription, des.Country, month(RequestedShipDate) as 'Month', ItemOrderedQuantity
from FS_COLine co
join FS_Item it on co.ItemKey = it.ItemKey
left outer join FIN_PLANCAP_2..ProductDescriptions des on it.ItemNumber collate database_default = des.RICNum
where RequestedShipDate >= convert(datetime, '01/01/2016', 120) and
RequestedShipDate <= convert(datetime, '12/31/2016', 120) and
isNumeric(it.ItemNumber) = 1 and
isNumeric(des.RICNum) = 1
--and it.ItemNumber = 35191305
group by ItemNumber, des.[Product Family], ItemDescription, des.Country, month(RequestedShipDate), ItemOrderedQuantity
order by ItemNumber
)A

how to include dates where no value

I have a query like so -
select CAST(jobrun_proddt as Date) as 'Date', COUNT(*) as 'Error Occurred Jobs' from jobrun
where jobrun_orgstatus = 66 and jobmst_type <> 1
group by jobrun_proddt
order by jobrun_proddt desc
Not every date will have a count. What I want to be able to do is the dates that are blank to have a count of 0 so the chart would look like this -
2014-11-18 1
2014-11-17 0
2014-11-16 0
2014-11-15 0
2014-11-14 0
2014-11-13 1
2014-11-12 0
2014-11-11 1
Currently it's not returning the lines where there's no count.
2014-11-18 1
2014-11-13 1
2014-11-11 1
edit to add that the jobrun table DOES have all the dates, just some dates don't have the value I'm searching for.
If you have data for all dates, but the other dates are being filtered by the where clause, then you can use conditional aggregation:
select CAST(jobrun_proddt as Date) as [Date],
SUM(CASE WHEN jobrun_orgstatus = 66 and jobmst_type <> 1 THEN 1 ELSE 0
END) as [Error Occurred Jobs]
from jobrun
group by jobrun_proddt
order by jobrun_proddt desc
Try this. Use Recursive CTE to generate the Dates.
WITH cte
AS (SELECT CONVERT(DATE, '2014-11-18') AS dates --Max date
UNION ALL
SELECT Dateadd(dd, -1, dates)
FROM cte
WHERE dates > '2014-11-11') -- Min date
SELECT a.dates,
Isnull([Error_Occurred_Jobs], 0)
FROM cte a
LEFT JOIN (SELECT Cast(jobrun_proddt AS DATE) AS Dates,
Count(*) AS [Error_Occurred_Jobs]
FROM jobrun
WHERE jobrun_orgstatus = 66
AND jobmst_type <> 1
GROUP BY jobrun_proddt) B
ON a.dates = b.dates
Order by a.dates desc
You'll have to join to a table or list of generated sequential dates using OUTER JOIN so that for the dates with no matches to your jobrun_orgstatus you can use ISNULL or COALESCE to return 0.
firstly, you must specify a particular date range
then you should connect your table with "left join"
DECLARE #start DATE, #end DATE;
SELECT #start = '20141114', #end = '20141217';
;WITH n AS
(
SELECT TOP (DATEDIFF(DAY, #start, #end) + 1)
n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_objects
)
SELECT 'Bob', DATEADD(DAY, n-1, #start) as 'xdate' FROM n;
select CAST(jobrun_proddt as Date) as 'Date', COUNT(*) as 'Error Occurred Jobs' from jobrun
left join n on DATEADD(DAY, n-1, #start) = jobrun.jobrun_proddt
where jobrun_orgstatus = 66 and jobmst_type <> 1
group by jobrun_proddt
order by jobrun_proddt desc

SQL query to return data corresponding to all values of a column except for the min value of that column

I have a table with the following columns:
userid, datetime, type
Sample data:
userid datetime type
1 2013-08-01 08:10:00 I
1 2013-08-01 08:12:00 I
1 2013-08-01 08:12:56 I
I need to fetch data for only two rows other than the row with min(datetime)
my query to fetch data for min(datetime) is :
SELECT
USERID, MIN(CHECKTIME) as ChkTime, CHECKTYPE, COUNT(*) AS CountRows
FROM
T1
WHERE
MONTH(CONVERT(DATETIME, CHECKTIME)) = MONTH(DATEADD(MONTH, -1,
CONVERT(DATE, GETDATE())))
AND YEAR(CONVERT(DATETIME, CHECKTIME)) = YEAR(GETDATE()) AND USERID=35
AND CHECKTYPE='I'
GROUP BY
CONVERT(DATE, CHECKTIME), USERID, CHECKTYPE
HAVING
COUNT(*) > 1
a lil help'll be much appreciated..thnx
Maybe something like this will help you:
WITH CTE AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY userid ORDER BY checktime) RN
FROM dbo.T1
WHERE CHECKTYPE = 'I'
--add your conditions here
)
SELECT * FROM CTE
WHERE RN > 1
Using CTE and ROW_NUMBER() function this will select all rows except min(date) for each user.
SQLFiddle DEMO
SELECT * FROM YOURTABLE A
INNER JOIN
(SELECT USERID,TYPE,MIN(datetime) datetime FROM YOURTABLE GROUP BY USERID,TYPE )B
ON
A.USERID=B.USERID AND
A.TYPE=B.TYPE
WHERE A.DATETIME<>B.DATETIME