SQL: Display Distinct Record From A Column - sql

Sample Data:
LogID OrderNo MaxDate AnotherDate Status
NULL 1 2013-07-30 12:01:00 NULL Pending
NULL 1 2013-07-30 12:01:01 NULL Pending
NULL 1 2013-07-30 12:01:02 NULL Pending
NULL 2 2013-07-30 12:02:00 NULL Pending
NULL 3 2013-08-01 12:30:00 NULL Pending
Expected Output:
LogID OrderNo MaxDate AnotherDate Status
NULL 1 2013-07-30 NULL Pending
NULL 2 2013-07-30 NULL Pending
NULL 3 2013-08-30 NULL Pending
LogID and OrderNo are both foreign keys. Data type for MaxDate is DateTime
UPDATE
Tried using this SQL statement:
SELECT DISTINCT(OrderNo), LogID, MaxDate, AnotherDate, Status
FROM Logs
but is still displaying 3 Order No 1's

I think select distinct * from <your table> will work for you
In your case with different times, you could use:
select distinct
LogID,
OrderNo,
cast(MaxDate as date) as MaxDate,
AnotherDate,
Status
from <your table>

I think what you're looking for is something like this:
SELECT [LOGID],
[ORDERNO],
Max([MAXDATE]) MaxDate,
[ANOTHERDATE],
[STATUS]
FROM Logs
GROUP BY [LOGID],
[ORDERNO],
[ANOTHERDATE],
[STATUS]
Take a look at this SQL Fiddle for an example.

Select LogId,
OrderNo,
Cast( MaxdATE as Date) as MaxdATE ,
AnotherDate,
Status from
(
Select LogId,
OrderNo,
MaxdATE,
AnotherDate,
Status,
Row_Number() Over( Partition by OrderNo Order by MaxDate Desc) as Row
from TableName
) T where T.Row=1

I think this is enough for your requirement
SELECT DISTINCT
LogID ,
OrderNo,
MaxDate ,
AnotherDate,
Status
FROM table
or if you want to take distinct based on your foreign key you may use this
;WITH cte AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY LogID ,OrderNo ORDER BY MaxDate ) AS rno,
LogID ,
OrderNo,
MaxDate ,
AnotherDate,
Status
FROM table
)
SELECT * FROM cte WHERE rno =1

Related

SQL Server : remove duplicates and add columns

I have a table which has duplicate record this is how the table looks like.
ID Date Status ModifiedBy
------------------------------------------
1 1/2/2019 10:29 Assigned(0) xyz
1 1/2/2019 12:21 Pending(1) abc
1 1/4/2019 11:42 Completed(5)abc
1 1/20/2019 2:45 Closed(8) pqr
2 9/18/2018 10:05 Assigned(0) xyz
2 9/18/2018 11:15 Pending(1) abc
2 9/21/2018 11:15 Completed(5)abc
2 10/7/2018 2:46 Closed(8) pqr
What I want to do is take the minimum date value but also I want to add additional column which is PendingStartDate and PendingEndDate.
PendingStartDate: date when ID went into pending status
PendingEndDate: date when ID went from pending status to any other status
So my final output should look like this
ID AuditDate Status ModifiedBy PendingStartDate PendingEndDate
---------------------------------------------------------------------------
1 1/2/2019 10:29 Assigned(0) xyz 1/2/2019 12:21 1/4/2019 11:42
2 9/18/2018 10:05 Assigned(0) abc 9/18/2018 11:15 9/21/2018 11:15
Any help as to how to do this is appreciated.
Thanks
I think you want conditional aggregation:
select id, min(date) as auditdate,
max(case when seqnum = 1 then status end) as status,
max(case when seqnum = 1 then modifiedBy end) as modifiedBy,
min(case when status like 'Pending%' then date end) as pendingStartDate,
max(case when status like 'Pending%' then next_date end) as pendingEndDate
from (select t.*,
row_number() over (partition by id order by date) as seqnum,
lead(date) over (partition by id order by date) as next_date
from t
) t
group by id;
please try this:
Declare #Tab Table(Id int, [Date] DATETIME,[Status] Varchar(25),ModifiedBy varchar(10))
Insert into #Tab
SELECT 1,'1/2/2019 10:29','Assigned(0)','xyz' Union All
SELECT 1,'1/2/2019 11:29','Started(0)','xyz' Union All
SELECT 1,'1/2/2019 12:21','Pending(1)','abc' Union All
SELECT 1,'1/2/2019 12:21','In-Progress(1)','abc' Union All
SELECT 1,'1/4/2019 11:42','Completed(5)','abc'Union All
SELECT 1,'1/20/2019 2:45','Closed(8)','pqr' Union All
SELECT 2,'9/18/2018 10:05','Assigned(0)','xyz'Union All
SELECT 2,'9/18/2018 11:15','Pending(1)','abc' Union All
SELECT 2,'9/21/2018 11:15','Completed(5)','abc' Union All
SELECT 2,'10/7/2018 2:46','Closed(8)','pqr'
;with cte As
(
Select * ,lead(date) over (partition by id order by date) as pendingStartDate
from #Tab
Where Status in ('Assigned(0)','Pending(1)','Completed(5)')
)
,cte2 As
(
Select * , lead(pendingStartDate) over (partition by id order by date) As pendingEndDate
from cte
)
Select * from cte2 where Status ='Assigned(0)'
As you mentioned in comment, i have included few states between Assigned,pending and completed.

Filtering a query with subqueries

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

SQL - Get oldest date while date is in where clause

Suppose I have this data
userid logdate event
0 2009-01-01 x
1 2010-01-01 x
1 2011-01-01 xy
1 2011-01-05 xz
2 2011-01-21 xx
2 2011-01-22 xx
I need to get users who made a log between 2011-01-01 and 2011-02-01
including their first logdate since beginning.
Expected result
userid first_logdate
1 2010-01-01
2 2011-01-21
Current solution
SELECT user_id, first_logdate
FROM (
SELECT user_id, logdate, MIN(logdate) AS first_logdate
FROM tablex
GROUP BY 1
)
WHERE logdate BETWEEN '2011-01-01' AND '2011-02-01'
If the data is large, is this query optimized?
GROUP BY the userid and get the MIN date as their first log date
SELECT userid, MIN(logdate) AS first_logdate
FROM table
WHERE logdate BETWEEN '2011-01-01' AND '2011-01-21'
GROUP BY userid
Use Group By and Min Aggregate
SELECT DISTINCT userid,
(SELECT Min(first_logdate)
FROM yourtable B
WHERE a.userid = b.userid)
FROM yourtable A
WHERE first_logdate BETWEEN '2011-01-01' AND '2011-02-01'
Try:
SELECT userid, MIN(logdate) AS first_logdate
FROM table
WHERE userid IN (
SELECT userid FROM table
WHERE logdate BETWEEN '2011-01-01' AND '2011-01-21'
)
GROUP BY userid
A self join may also be used:
SELECT userid, MIN(t1.logdate) AS first_logdate
FROM table t1
JOIN table t2 USING ( userid )
WHERE t2.logdate BETWEEN '2011-01-01' AND '2011-01-21'
GROUP BY userid
and a third version using EXISTS operator
SELECT userid, MIN(logdate) AS first_logdate
FROM table t1
WHERE EXISTS (
SELECT 555821 FROM table t2
WHERE t2.logdate BETWEEN '2011-01-01' AND '2011-01-21'
AND t1.userid = t2.userid
)
GROUP BY userid

Getting most recent distinct records

Considering the following table:
User CreatedDateTime Quantity
----- ----------------- --------
Jim 2012-09-19 01:00 1
Jim 2012-09-19 02:00 5
Jim 2012-09-19 03:00 2
Bob 2012-09-19 02:00 2
Bob 2012-09-19 03:00 9
Bob 2012-09-19 05:00 1
What query would return the most recent rows (as defined by CreatedDateTime) for each User, so that we could determine the associated Quantity.
i.e. the following records
User CreatedDateTime Quantity
----- ----------------- --------
Jim 2012-09-19 03:00 2
Bob 2012-09-19 05:00 1
We thought that we could simply Group By User and CreatedDateTime and add a Having MessageCreationDateTime = MAX(.MessageCreationDateTime. Of course this does not work because Quantity is not available following the Group By.
Since you are using SQL Server, you can use Window Function on this.
SELECT [User], CreatedDateTime, Quantity
FROM
(
SELECT [User], CreatedDateTime, Quantity,
ROW_NUMBER() OVER(PARTITION BY [User] ORDER BY CreatedDateTime DESC) as RowNum
FROM tableName
) a
WHERE a.RowNum = 1
SQLFiddle Demo
;WITH x AS
(
SELECT [User], CreatedDateTime, Quantity,
rn = ROW_NUMBER() OVER (PARTITION BY [User] ORDER BY CreatedDateTime DESC)
FROM dbo.table_name
)
SELECT [User], CreatedDateTime, Quantity
FROM x WHERE rn = 1;
If you do not have the ability to use windowing functions, then you can use a sub-query:
select t1.[user], t2.mxdate, t1.quantity
from yourtable t1
inner join
(
select [user], max(CreatedDateTime) mxdate
from yourtable
group by [user]
) t2
on t1.[user]= t2.[user]
and t1.CreatedDateTime = t2.mxdate
see SQL Fiddle with Demo
SELECT DISTINCT
User,
CreatedDateTime,
Quantity
FROM
YourTable
WHERE
CreatedDateTime =
(SELECT MAX(CreatedDateTime) FROM YourTable t WHERE t.User = YourTable.User)
select * from <table_name> where CreatedDateTime in (select max(CreatedDateTime) from <table_name> group by user) group by user;

Need help finding the correct T-SQL Query

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;