How to extract the latest rows - sql

I have a table like this:
Table A
Date Time ID Ref
110217 91703 A001 A1100056
110217 91703 A001 A1100057
110217 91703 A001 A1100058
110217 91703 A001 A1100059
110217 132440 A001 A1100057
110217 132440 A001 A1100058
110217 132440 A001 A1100060
110217 91703 B001 B1100048
110217 91703 B001 B1100049
110217 132440 B001 B1100049
110217 132440 B001 B1100050
I wish to have the latest data only & the final result should look like this using SQL:
Date Time ID Ref
110217 132440 A001 A1100057
110217 132440 A001 A1100058
110217 132440 A001 A1100060
110217 132440 B001 B1100049
110217 132440 B001 B1100050
(3 records all with the same "latest" time)
The database will self-update by itself at certain time. The problem is: I do not know the exact time, hence I do not know which record is the latest.

This works in SQL Server:
SELECT TOP 1 WITH TIES *
FROM TableA
ORDER BY Date DESC, Time DESC
And this solution is probably server-independent:
SELECT a.*
FROM TableA a
JOIN (
SELECT d.MaxDate, MAX(t.Time) AS MaxTime
FROM TableA t
JOIN (
SELECT MAX(Date) AS MaxDate
FROM TableA
) d
ON t.Date = d.MaxDate
GROUP BY d.MaxDate
) m
ON a.Date = m.MaxDate AND a.Time = m.MaxTime

SELECT * FROM table ORDER BY date DESC, time DESC LIMIT 1;
Will give you the latest row in MySql.

Which database are you using? You can actually concat the two columns after converting them to a date and time format, and then order by date. All this can be achieved in query.

Related

Query to group all the rows with same column value

userid
tenantid
null
a001
null
a002
null
a002
null
a002
null
a001
null
a003
null
a002
null
a003
null
a001
null
a002
I want to set the userid as "distinct_user_#" for the rows with same tenant ids. I can't set the userid manually as tenantids are generated randomly
So output would be something like
userid
tenantid
d_u_1
a001
d_u_2
a002
d_u_2
a002
d_u_3
a003
d_u_1
a001
d_u_3
a003
d_u_2
a002
d_u_3
a003
d_u_1
a001
d_u_2
a002
Any help with this?
We can use DENSE_RANK() here:
SELECT 'd_u_' + CAST(DENSE_RANK() OVER (ORDER BY tenantid) AS varchar(12)) AS userid,
tenantid
FROM yourTable;
You can use the dense_rank function to generate this id:
SELECT 'd_u_' + DENSE_RANK() OVER (PARTITION BY tenantid ORDER BY tenantid) AS userid,
tenantid
FROM mytable

SQL Query to Count total rows grouping different columns

I have a database that has RMA return data. I want to write a query to return the total number of times a unit has been returned (each return has a unique RMA Number). I also need to return the number of times a unit has returned multiple times, and the number of times it returned for the same symptom. A record is created each time the unit goes to a station (RMA, symptom, and date returned is propagated for each station record).
The data looks like this:
ID SN RMA SYMPTOM Station Date_Returned
21567 A001 84704 POWER FAULT DockRecv 01/01/2015
21568 A001 84704 POWER FAULT Repair 01/01/2015
21569 A001 84704 POWER FAULT Ship 01/01/2015
10235 A002 83494 NO DISPLAY DockRecv 02/20/2015
10236 A002 83494 NO DISPLAY Repair 02/20/2015
10237 A002 83494 NO DISPLAY Ship 02/20/2015
36548 A002 84283 ABNORMAL NOISE DockRecv 10/05/2015
36549 A002 84283 ABNORMAL NOISE Repair 10/05/2015
36550 A002 84283 ABNORMAL NOISE Ship 10/05/2015
38790 A003 83432 HDD FAULT DockRecv 09/15/2015
38791 A003 83432 HDD FAULT Repair 09/15/2015
38792 A003 83432 HDD FAULT Ship 09/15/2015
69613 A003 84276 HDD FAULT DockRecv 01/30/2016
69614 A003 84276 HDD FAULT Repair 01/30/2016
69615 A003 84276 HDD FAULT Ship 01/30/2016
56732 A004 82011 NFF DockRecv 12/01/2015
56733 A004 82011 NFF Repair 12/01/2015
56734 A004 82011 NFF Ship 12/01/2015
My Output needs to look like this:
Total_Returns Repeat_Return Same_Symptom_Return
6 2 1
A001(RMA 84704) is a single return.
A002 is a multiple return-(RMA 83494) is the first return (after repaired, the unit is shipped out) after some time in the field, the unit is returned again A002(RMA 84283).... When a unit is returned, it goes through 3 stations (we create a record for each station (propagating the RMA, symptom, and date returned for each station record).
I can get Total_Returns with the code:
Select count(*) as totalcount
From
(
SELECT
[SN]
,[RMA]
FROM [dbo].[test]
Group by [SN],[RMA]
)as a
There are 3 quite different methods needed to arrive at the counts, so I have used 3 separate sub-queries. see this working at sqlfiddle (but not on MS SQL Server) here: http://sqlfiddle.com/#!5/9df16/1
Result:
| Total_Count | Repeat_Return | Same_Symptom_Return |
|-------------|---------------|---------------------|
| 6 | 2 | 1 |
Query:
select
(select count(distinct SN + RMA + SYMPTOM) from table1) as Total_Count
, (select count(*) from(
SELECT SN
FROM table1
Group by SN
having count(distinct Date_Returned) > 1)
) as Repeat_Return
, (select count(*) from(
SELECT SYMPTOM
FROM table1
Group by SYMPTOM
having count(*)/3 > 1)
) as Same_Symptom_Return
note: you should include "sql server" as a tag on your question (well I presum it is that because of the [dbo].[test]
I got it to work... I'm sure there is a more streamline way to write it...
SELECT
-- Get Total_Returned Count
(Select distinct
count(*) as 'Total_Returned'
From
( SELECT
[SN]
,[RMA]
FROM [dbo].[test]
Group by [SN],[RMA]
)a) AS 'Total_Returned'
-- Get Repeat_Return Count
,(Select distinct
[Repeat_Return] - COUNT(*) OVER() AS [Repeat_Return]
From
( SELECT
COUNT(*) OVER() AS [Repeat_Return]
,[SN]
,[RMA]
FROM [dbo].[test]
Group by [SN],[RMA]
)a Group by [SN],[Repeat_Return]) AS 'Repeat_Return'
-- Get Same_Symptom_Return Count
,(Select distinct
[Same_Symptom_Return] - COUNT(*) OVER() AS [Same_Symptom_Return]
From
( SELECT
COUNT(*) OVER() AS [Same_Symptom_Return]
,[SN]
,[RMA]
,SYMPTOM
FROM [dbo].[test]
Group by SN, SYMPTOM, RMA
)a Group by [SN], SYMPTOM, [Same_Symptom_Return]) AS 'Same_Symptom_Return'
Result:
|Total_Returned | Repeat_Return | Same_Symptom_Return |
|---------------|---------------|---------------------|
| 6 | 2 | 1 |

Subtition of cursor for combining tables with time periods

I have to combine two tables into one but I have to take validation dates into consideriation. For instance having two tables:
Address
ID AddressValue ValidFrom ValidTo
----------- --------------- ----------------------- -----------------------
1 Pink Street 2010-01-01 00:00:00.000 2010-01-20 00:00:00.000
2 Yellow Street 2010-01-20 00:00:00.000 2010-02-28 00:00:00.000
Phone
ID PhoneValue ValidFrom ValidTo
----------- ------------ ----------------------- -----------------------
1 123456789 2010-01-01 00:00:00.000 2010-01-15 00:00:00.000
2 987654321 2010-01-16 00:00:00.000 2010-01-31 00:00:00.000
I need to do combine them into new one:
NewSystem
ID NewPhone NewAddress ValidFrom ValidTo Version
----------- ----------- --------------- ----------------------- ----------------------- -------
1 123456789 Pink Street 2010-01-01 00:00:00.000 2010-01-15 00:00:00.000 4
2 NULL Pink Street 2010-01-15 00:00:00.000 2010-01-16 00:00:00.000 3
3 987654321 Pink Street 2010-01-16 00:00:00.000 2010-01-20 00:00:00.000 2
4 987654321 Yellow Street 2010-01-20 00:00:00.000 2010-01-31 00:00:00.000 1
5 NULL Yellow Street 2010-01-31 00:00:00.000 2010-02-28 00:00:00.000 0
The idea is quite simple. I create periods based on dates and then query each table in subqueries. I pasted my solution here: http://pastebin.com/cdKePA9X.
Right now I am trying to get rid of the cursor but I failed. I tried to use CTE but without success. Maybe someone of you faced similar problem or know how to combine these tables into one without using cursor. I pasted the 'create table' scripts here: http://pastebin.com/BeRspb6K.
Thank you in advanced.
First, construct new date ranges by merging the date ranges from the source tables. Second, for each new date range, lookup the valid data in the source tables.
WITH
old_ranges(d1,d2) AS (
SELECT ValidFrom,ValidTo FROM #Address UNION
SELECT ValidFrom,ValidTo FROM #Phone
),
new_ranges(d1,d2) AS (
SELECT d,LEAD(d) OVER(ORDER BY d)
FROM (
SELECT DISTINCT d
FROM old_ranges
UNPIVOT(d FOR dx IN (d1,d2)) p
) t
)
SELECT
ROW_NUMBER() OVER (ORDER BY d1) AS ID,
NewPhone,
NewAddress,
d1 AS ValidFrom,
d2 AS ValidTo
FROM new_ranges
OUTER APPLY (
SELECT PhoneValue AS NewPhone
FROM #Phone
WHERE ValidFrom <= d1 AND ValidTo >= d2
) x1
OUTER APPLY (
SELECT AddressValue AS NewAddress
FROM #Address
WHERE ValidFrom <= d1 AND ValidTo >= d2
) x2
WHERE d2 IS NOT NULL

SQL query to retrieve only one occurrence for each id

This is my (simplified) table:
id eventName seriesKey eventStart
1 Event1 5000 2012-01-01 14:00:00
2 Event2 5001 2012-01-01 14:30:00
3 Event3 5000 2012-01-01 14:50:00
4 Event4 5002 2012-01-01 14:55:00
5 Event5 5001 2012-01-01 15:00:00
6 Event6 5002 2012-01-01 15:30:00
7 Event7 5002 2012-01-01 16:00:00
I have to build a query that orders the table by eventStart (ASC) but for each seriesKey, I need only one occurrence.
Thank you very much
Try aggregating with GROUP BY and using aggregate functions like MIN().
SELECT seriesKey,
MIN(eventStart) eventStart
FROM events
GROUP BY seriesKey;
This results in:
5000 2012-01-01 14:00:00.000
5001 2012-01-01 14:30:00.000
5002 2012-01-01 14:30:00.000
If your're interested in all columns from events table, not just the above two columns I choose, there's a freaky implementation in some databases (e.g. SQL Server) which may help you:
SELECT *
FROM events e1
WHERE e1.ID IN
(
SELECT TOP 1 e2.ID
FROM events e2
WHERE e2.seriesKey = e1.seriesKey
ORDER BY e2.eventStart
);
Resulting in:
1 Event1 5000 2012-01-01 14:00:00.000
2 Event2 5001 2012-01-01 14:30:00.000
6 Event2 5002 2012-01-01 14:30:00.000
If you also need the other columns associated with the key, you have two options:
select *
from (
select id,
eventName,
seriesKey,
eventStart,
row_number() over (partition by seriesKey order by eventStart) as rn
from the_event_table
) t
where rn = 1
order by eventStart
or for older DBMS that do not support windowing functions:
select t1.id,
t1.eventName,
t1.seriesKey,
t1.eventStart
from the_event_table t1
where t1.eventStart = (select min(t2.eventStart)
from the_event_table t2
where t2.seriesKey = t1.seriesKey)
order by eventStart
you can get earlier date for each seriesKey:
select * from
(
select seriesKey, min(eventStart) as mindate
group by seriesKey
)
order by mindate

Compare with Date and ID problem

Table1
ID Date Intime Outtime
A001 20000501 12:00:00 22:00:00
A001 20000502 14:00:00 22:00:00
A001 20000503 12:00:00 23:00:00
A002 20000501 11:00:00 20:00:00
A002 20000502 13:00:00 21:00:00
So on…,
Table2
ID Date Intime Outtime
A001 20050501 14:00:00 23:00:00
A002 20050501 08:00:00 16:00:00
From the above table
I want to take Table1.ID, Table1.Date, Table2.Intime, Table2.Outtime from Table1 Inner Join Table2 on Table1.ID = Table2.ID and Table1.Date = Table2.Date
Getting Duplicated values
ID Date Intime Outtime
A001 20000501 14:00:00 23:00:00
A001 20000501 18:00:00 16:00:00
A002 20000501 14:00:00 23:00:00
A002 20000501 18:00:00 16:00:00
I tried Left outer Join also. It was showing a same. How to compare the id and date.
Need query Help?
If you do an inner join, you'll only get those rows that are present in both tables (in terms of their ID and Date):
SELECT
Table1.ID, Table1.Date,
Table2.Intime, Table2.Outtime
FROM Table1
INNER JOIN Table2 ON Table1.ID = Table2.ID AND Table1.Date = Table2.Date
ID Date InTime OutTime
A001 20000501 14:00:00 23:00:00
A002 20050501 08:00:00 16:00:00
If you're not getting this, then there's a problem in your data - as I've already mentioned in a previous answer to a previous question.
Check the output of this query:
SELECT * FROM Table2 WHERE ID = 'A001' AND Date = '20000501'
I bet you get more than one row.....
Marc
Trying to explain further - I still think you're misunderstanding the INNER JOIN or you're trying to accomplish something that can't really be done easily.
Your output is something like this:
ID Date Intime Outtime
A001 20000501 14:00:00 23:00:00
A001 20000501 18:00:00 16:00:00
A002 20000501 14:00:00 23:00:00
A002 20000501 18:00:00 16:00:00
If you truly get this output from your INNER JOIN, then this means:
you most like have one row with ID=A001 and Date=20000501 in your Table1
you have two (or more) rows in your Table2 with ID=A001 and Date=20000501
What the INNER JOIN will do is combine row#1 from Table2 with the single row from Table1, and then row#2 from Table2 with the single row from Table1, and so on.
If you have multiple entries with the same (ID,Date) values in Table2, you will get duplicates with an INNER JOIN - this is by design, and is not an error - but just the way the INNER JOIN works.