Need help finding the correct T-SQL Query - sql

I am not quite sure how to go about doing this. Basically I have have a table like this
UserId DateRequested Approved ApprovedBy Notes
------------ ----------------------- -------- ----------- -----
1 2011-05-26 0 NULL NULL
1 2011-05-27 0 NULL NULL
1 2011-05-28 0 NULL NULL
1 2011-06-05 0 NULL NULL
1 2011-06-06 0 NULL NULL
1 2011-06-25 0 NULL NULL
Which basically contains the days an employee requests a holiday. Now, when a day or days is granted, this data needs to be copied over to a table of the form
UserId DateFrom DateTo
So basically for the above data i want:
UserId DateFrom DateTo
-------------------------------
1 2011-05-26 2011-05-28
1 2011-06-05 2011-06-06
1 2011-06-25 2011-06-25
I.e I want consecutive days in the DateFrom and DateTo. Now I am not sure how to do this without using a while loop. This is SQL, So i would prefer a non-iterative solution.
Please advise!!!

;WITH cte AS
(
SELECT *,
DATEDIFF(DAY,0,DateRequested)-
ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY DateRequested) AS Grp
FROM YourTable
WHERE Approved = 1 /*Presumably - but your example data doesn't show this.*/
)
SELECT UserId,
MIN(DateRequested) AS DateFrom,
MAX(DateRequested) AS DateTo
FROM cte
GROUP BY UserId,Grp

In Oracle PL/SQL it would be written as follows:
WITH cte
AS (SELECT a.*,
daterequested - TRUNC (SYSDATE)
- ROW_NUMBER ()
OVER (PARTITION BY UserId ORDER BY DateRequested)
AS Grp
FROM yourtable a
WHERE Approved = 0)
SELECT UserId, MIN (DateRequested) AS DateFrom, MAX (DateRequested) AS DateTo
FROM cte
GROUP BY UserId, Grp;

Related

How to get the row for the current date?

Pretend today 2022-10-24
case 1
id
productCode
version
startDate
endDate
1
AAA
1
2022-10-01
2022-10-28
2
AAA
2
2022-10-29
NULL
case 1 depend on table above, I want to return only 1 row at id 1, why cause today 2022-10-24 still between startDate and endDate
case 2
id
productCode
version
startDate
endDate
1
AAA
1
2022-10-01
2022-10-28
2
AAA
2
2022-10-01
NULL
case 2 depends on table above. I want to return only 1 row at id 2. Why cause when startDate has the same value between id 1 & 2, so choose endDate with NULL value.
I am still confused about how to implement this with query.
I want to make for one query logic. When running query so when use case 1 return id 1 and when I use for case 2 return id 2.
As I mention in the comments, seems you just need some simple >= and <(=) logic (while handling NULLs) and a "Top 1 per group":
WITH CTE AS(
SELECT id,
productCode,
version,
startDate,
endDate,
ROW_NUMBER() OVER (PARTITION BY productCode ORDER BY Version DESC) AS RN --Guessed the required partition and order clauses
FROM dbo.YourTable
WHERE startDate <= CONVERT(date,GETDATE())
AND (endDate >= CONVERT(date,GETDATE()) OR endDate IS NULL))
SELECT id,
productCode,
version,
startDate,
endDate
FROM CTE
WHERE RN = 1;

SQL active users by month

I would like to know the number of active users by month, I use SQL Server 2017.
I have an AuditLog table like:
- UserID: int
- DateTime: datetime
- AuditType: int
UserID DateTime AuditType
------------------------------
1 2022-01-01 1
1 2022-01-15 4
1 2022-02-20 3
2 2022-01-10 8
2 2022-03-10 1
3 2022-03-20 1
If someone has at least one entry in a given month then he/she is treated as active.
I would like to have a result like:
Date Count
2022-01 2
2022-02 1
2022-03 2
I think you can combine the function Month(datetime) in the GROUP BY with the Count function SELECT COUNT(UserID)
SELECT (CAST(YEAR(C.DATE)AS CHAR(4))+'-'+CAST(MONTH(C.DATE)AS CHAR(2)))YEAR_MONTH,COUNT(C.USER_ID)CNTT
FROM AUDITLOG AS C
GROUP BY (CAST(YEAR(C.DATE)AS CHAR(4))+'-'+CAST(MONTH(C.DATE)AS CHAR(2)))
ORDER BY (CAST(YEAR(C.DATE)AS CHAR(4))+'-'+CAST(MONTH(C.DATE)AS CHAR(2)));
Here is solutions,
Select [Date],count(1) as Count From (
select Cast(cast(d.DateTime as date) as varchar(7)) as [Date],UserId
from AuditLog d
Group by Cast(cast(d.DateTime as date) as varchar(7)),UserId
) as q1 Group by [Date]
Order by 1
Hope, it will works.
GROUP DATE (Year and Month) either combine or separate and count distinct userId
SELECT CONVERT(VARCHAR(7), [DateTime], 126)[Date], COUNT(DISTINCT UserID)[Count]
FROM AuditLog
GROUP BY CONVERT(VARCHAR(7), [DateTime], 126)

Get latest entry in each week over several years period

I have the following table to store history for entities:
Date Id State
-------------------------------------
2017-10-10 1 0
2017-10-12 1 4
2018-5-30 1 8
2019-4-1 2 0
2018-3-6 2 4
2018-3-7 2 0
I want to get last entry for each Id in one week period e.g.
Date Id State
-------------------------------------
2017-10-12 1 4
2018-5-30 1 8
2019-4-1 2 0
2018-3-7 2 0
I'd try to use Partition by:
select
ID
,Date
,State
,DatePart(week,Date) as weekNumber
from TableA
where Date = (
select max(Date) over (Partition by Id Order by DatePart(week, Date) Desc)
)
order by ID
but it still gives me more than one result per week.
You can use ROW_NUMBER():
SELECT a.*
FROM (SELECT a.*, ROW_NUMBER() OVER (PARTITION BY a.id, DATEPART(WK, a.Date) ORDER BY a.Date DESC) AS Seq
FROM tablea a
) a
WHERE seq = 1
ORDER BY id, Date;

#SQL - Order By matching record first

i need help to order this table (named "season") , by matching actual date with the BEGINDATE
ID NAME BEGINDATE
----------- -------------------- ----------
1 2014-2015 2014-10-01
2 2015-2016 2015-10-01
3 2016-2017 2016-10-01
4 2017-2018 2017-10-01
for example:
actual date is 2016/10/28 so we are in season 2016-2017 (id=3)
so the result should be
ID NAME BEGINDATE
----------- -------------------- ----------
3 2016-2017 2016-10-01
1 2014-2015 2014-10-01
2 2015-2016 2015-10-01
4 2017-2018 2017-10-01
UPDATE (SOLVED)
what i finally did was:
DECLARE #IDACTIVE AS INT = (SELECT MAX(ID) FROM SEASON WHERE BEGINDATE < GETDATE())
SELECT
1 AS ORDERBY,
ID,
NAME,
BEGINDATE
FROM SEASON
WHERE ID = #IDACTIVE
UNION
SELECT
2 AS ORDERBY,
ID,
NAME,
BEGINDATE
FROM SEASON
WHERE ID = #IDACTIVE
Follow the next approach:
1) Get The only matched row by using Top and Where clauses.
2) Get the all records except the one that you getting on point #1
3) Combine the result of two Selects via using UNION ALL.
Demo:-
Create table season (id int , NAME varchar(20),BEGINDATE date)
go
insert into season values (1,'2014-2015','2014-10-01')
insert into season values (2,'2015-2016','2015-10-01')
insert into season values (3,'2016-2017','2016-10-01')
insert into season values (4,'2017-2018','2017-10-01')
go
select * from (
select top 1 * from season
where BEGINDATE < getdate()
order by BEGINDATE desc
) a
union all
select * from season
where BEGINDATE != (
select top 1 BEGINDATE from season
where BEGINDATE < getdate()
order by BEGINDATE desc)
-- an another Soluation
select * from season
where DATEPART(Year,BEGINDATE) =DATEPART(Year,getdate())
union all
select * from season
where DATEPART(Year,BEGINDATE) !=DATEPART(Year,getdate())
The Result:
First move all future dates to the end, then order by beginDate
SELECT *
FROM season
ORDER BY CASE WHEN beginDate > GETDATE() THEN 0 ELSE 1 END,
beginDate
I think this is most easily done using window functions:
select s.*
from season s
order by (case when begindate = max(case when getdate() >= begindate then begindate end) over ()
then 1 else 2
end),
id

SQL Server - MyCTE query based on 24 hour period (next day)

I have this bit of code:
;WITH MyCTE AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY CardUser ORDER BY CardTableID) AS NewVariation
FROM CardChecker
)
UPDATE MyCTE
SET Status = NewVariation
which currently updates the status column, however what I want to happen is over a 24 hour period, the status starts again the next day at 1, and counts again based on the CardUser like specified above:
Current data and what happens:
2 aaa 1 2015-06-25 08:00:00.000 123 1 NULL
3 ccc 1 2015-06-25 00:00:00.000 124 1 NULL
4 aaa 1 2015-06-25 17:30:00.000 125 2 NULL
5 aaa 1 2015-06-26 17:30:00.000 125 *3* NULL
what I want to happen:
2 aaa 1 2015-06-25 08:00:00.000 123 1 NULL
3 ccc 1 2015-06-25 00:00:00.000 124 1 NULL
4 aaa 1 2015-06-25 17:30:00.000 125 2 NULL
5 aaa 1 2015-06-26 17:30:00.000 125 *1* NULL
im not quite sure how I could add this to the above query so would it be possible for someone to point me in the right direction?
the main problem is the EventTime field contains both the date and the time, so adding it is as a PARTITION means the status would always be 1 based on the time parameter of the field
thanks for the help
Current CardTable structure:
CREATE TABLE CardTable (CardTableID INT IDENTITY (1,1) NOT NULL,
CardUser VARCHAR(50),
CardNumber VARCHAR(50),
EventTime DATETIME,
Status INT)
You can CONVERT() the EventTime to DATE type and then PARTITION:
;WITH MyCTE AS
(
SELECT Status,
ROW_NUMBER() OVER(PARTITION BY CardUser, CONVERT(DATE, EventTime)
ORDER BY CardTableID) AS NewVariation
FROM CardChecker
)
UPDATE MyCTE
SET Status = NewVariation
Your query basically unnecessarily updating entire table everytime. If EventTime is current date time of the system, having a flag to mark already updated status would improve the performance.
;WITH MyCTE AS
(
SELECT Status,
ROW_NUMBER() OVER(PARTITION BY CardUser, CONVERT(DATE, EventTime)
ORDER BY CardTableID) AS NewVariation
FROM CardChecker
WHERE Status IS NULL OR
CONVERT(DATE, EventTime) = CONVERT(DATE, GETDATE())
)
UPDATE MyCTE
SET Status = NewVariation