Max and Min records from 2 tables - sql

I have 2 tables.
The 1st table have the columns fileID, createdate.
The 2nd table have the userid, fileID, createdate as common fields along with other columns.
I am trying to write a query to find latest fileid(max) and the 1st loaded fileid(min) based on the createdate for a specific userid by joining both these tables and using groupby on fileid, createdate in the query and filtering the user id in the where clause.
However the result is showing all the rows.
I need a suggestion as how to write a query inorder to get 2 records(max and min fileid records) only from both these tables and not all the records with these field changes.
I am using SQL Server to write the query.
Thanks for your help.

To select fieldid by earliest or lattest createdate and to have it in two separate rows you can try something like this:
SELECT fileid, "earliest" as type FROM table1 WHERE createdate = (SELECT MIN(createdate) from table1) LIMIT 1
UNION ALL
SELECT fileid, "lattest" as type FROM table1 WHERE createdate = (SELECT MAX(createdate) from table1) LIMIT 1
It is not clear, why you want to join it with the second table, but you can do it like this:
SELECT
*
FROM
(
SELECT fileid, "earliest" as type FROM table1 WHERE createdate = (SELECT
MIN(createdate) from table1) LIMIT 1
UNION ALL
SELECT fileid, "lattest" as type FROM table1 WHERE createdate = (SELECT
MAX(createdate) from table1) LIMIT 1
) as subquery1
LEFT JOIN
table2 on table2.fileid = createdate.fileid

Related

SQL query to return rows where only one record is present in a given status

I have a table with data similar to below. I am trying to get a list of results that will display all rows where only one unique SourceID exists in status 10. If I were querying this table, I would expect ID's 3 and 4 to be returned.
Table Example
Select *
From table
Where Status = 10 and Source ID in
(
Select SourceID
From Table
Group by SourceID
Having Count(*) = 1
)
You can use NOT EXISTS :
SELECT t.*
FROM table t
WHERE NOT EXISTS (SELECT 1 FROM table t1 WHERE t1.SourceID = t.SourceID AND t1.Status <> t.Status);
Maybe that would work?
SELECT ID FROM Mytable
WHERE [Status] = 10
GROUP BY ID
HAVING COUNT(SourceID) = 1
First, find out all the unique SourceIDs
SELECT
SourceID
FROM
Data
GROUP BY
SourceID
HAVING
COUNT(SourceID) = 1
And then use this query as a sub query to get all the rows that has unique SourceID;
SELECT
*
FROM
Data
WHERE
SourceID IN (
SELECT
SourceID
FROM
Data
GROUP BY
SourceID
HAVING
COUNT(SourceID) = 1
)
Use a sub-query to check if t there is an exact count of 1 of those source id's
SELECT t.* FROM YourTable t WHERE t.status = 10
AND
(SELECT COUNT(0) x From YourTable t2
where t2.sourceid = t.sourceid) = 1

How to get Full Record with MAX as aggregate function

I have a table with schema (id, date, value, source, ticker). I wanted to get record having highest ID group by date in sql server
Example Data
ID|date|value|source|ticker
3|10-Dec-2017|10|a|b
1|10-Dec-2017|11|p|q
Below query works in Sqlite. Do we know if I can do same with SqlServer
select max(id), date, value, source, ticker from table group by date
Expected return:-
ID|date|value|source|ticker
3|10-Dec-2017|10|a|b
Also how I can do same operation on UNION of 2 tables with same schema.
You can use subquery :
select t.*
from table t
where id = (select max(t1.id) from table t1 where t1.date = t.date);
However, you can also use row_number() function :
select top (1) with ties *
from table t
order by row_number() over (partition by [date] order by id desc);
You can also do it like below :
select t1.* from table1 t1
join (
select max(id) as id, [date] from table1
group by [date]
) as t2 on t1.id = t2.id
SQL HERE

Count uid from two tables who look the same sort by tablename

since I am not as good with more complex SQL SELECT Statements I thought of just asking here, since it's hard to find something right on topic.
I got two tables who have exactly the same structure like
TABLE A (id (INT(11)), time (VARCHAR(10));)
TABLE B (id (INT(11)), time (VARCHAR(10));)
Now I want a single SELECT to count the entrys of an specific id in both tables.
SELECT COUNT(*) FROM TABLE A WHERE id = '1';
SELECT COUNT(*) FROM TABLE B WHERE id = '1';
So I thought it would be much better for the database performance if I use one SELECT instead of one.
Thanks for helping out
SELECT COUNT(*) as count, 'tableA' as table_name FROM TABLEA WHERE id = '1'
union all
SELECT COUNT(*), 'tableB' FROM TABLEB WHERE id = '1'
If you want the separate counts in a single row, you can use subqueries
SELECT
(SELECT COUNT(*) FROM TABLE A WHERE id = '1') a_count,
(SELECT COUNT(*) FROM TABLE B WHERE id = '1') b_count;
You could do it like:
select count(*)
from (
select id from t1 where id = 1
union all
select id from t2 where id = 1
) as t
Another alternative is:
select sum(cnt)
from (
select count(*) as cnt from t1 where id = 1
union all
select count(*) as cnt from t2 where id = 1
) as t

Get the most recently used date from two different tables with two different named columns

I've two tables say table 1 and table 2,
table 1 has column names as sno and useddate
table 2 has column names as sno and recentlyuseddate
I want to compare these two columns useddate and recentlyusedate and get the most recently used date.
These tables may have many entries but I need only ONE ENTRY (mostrecent) date after comparing these tables.
SELECT MAX(useddate) AS mostrecent
FROM
(SELECT useddate FROM Table1
UNION ALL
SELECT recentlyuseddate AS useddate FROM Table2) TheUnion
You can use unions for this
SELECT MAX(col)
FROM (SELECT col FROM TABLE_1
UNION ALL
SELECT col FROM TABLE_2)
If you have an index on the two dates in the two tables, I would go for:
select top 1 sno, useddate, which
from ((select top 1 sno, useddate, 'table1' as which from table1 order by useddate desc) union all
(select top 1 sno, recentlyuseddate , 'table2' as which from table2 order by recentlyuseddate desc)
)
order by useddate desc;
This version also tells you which table the date came from.

TSQL: Return row(s) with earliest dates

Given 2 tables called "table1" and "table1_hist" that structurally resemble this:
TABLE1
id status date_this_status
1 open 2008-12-12
2 closed 2009-01-01
3 pending 2009-05-05
4 pending 2009-05-06
5 open 2009-06-01
TABLE1_hist
id status date_this_status
2 open 2008-12-24
2 pending 2008-12-26
3 open 2009-04-24
4 open 2009-05-04
With table1 being the current status and table1_hist being a history table of table1, how can I return the rows for each id that has the earliest date. In other words, for each id, I need to know it's earliest status and date.
EXAMPLE:
For id 1 earliest status and date is open and 2008-12-12.
For id 2 earliest status and date is open and 2008-12-24.
I've tried using MIN(datetime), unions, dynamic SQL, etc. I've just reached tsql writers block today and I'm stuck.
Edited to add: Ugh. This is for a SQL2000 database, so Alex Martelli's answer won't work. ROW_NUMBER wasn't introduced until SQL2005.
SQL Server 2005 and later support an interesting (relatively recent) aspect of SQL Standards, "ranking/windowing functions", allowing:
WITH AllRows AS (
SELECT id, status, date_this_status,
ROW_NUMBER() OVER(PARTITION BY id ORDER BY date_this_status ASC) AS row,
FROM (SELECT * FROM Table1 UNION SELECT * FROM Table1_hist) Both_tables
)
SELECT id, status, date_this_status
FROM AllRows
WHERE row = 1
ORDER BY id;
where I'm also using the nice (and equally "new") WITH syntax to avoid nesting the sub-query in the main SELECT.
This article shows how one could hack the equivalent of ROW_NUMBER (and also RANK and DENSE_RANK, the other two "new" ranking/windowing functions) in SQL Server 2000 -- but that's not necessarily pretty nor especially well-performing, alas.
The following code sample is completely self-sufficient, just copy and paste it into a management studio query and hit F5 =)
DECLARE #TABLE1 TABLE
(
id INT,
status VARCHAR(50),
date_this_status DATETIME
)
DECLARE #TABLE1_hist TABLE
(
id INT,
status VARCHAR(50),
date_this_status DATETIME
)
--TABLE1
INSERT #TABLE1
SELECT 1, 'open', '2008-12-12' UNION ALL
SELECT 2, 'closed', '2009-01-01' UNION ALL
SELECT 3, 'pending', '2009-05-05' UNION ALL
SELECT 4, 'pending', '2009-05-06' UNION ALL
SELECT 5, 'open', '2009-06-01'
--TABLE1_hist
INSERT #TABLE1_hist
SELECT 2, 'open', '2008-12-24' UNION ALL
SELECT 2, 'pending', '2008-12-26' UNION ALL
SELECT 3, 'open', '2009-04-24' UNION ALL
SELECT 4, 'open', '2009-05-04'
SELECT x.id,
ISNULL(y.[status], x.[status]) AS [status],
ISNULL(y.date_this_status, x.date_this_status) AS date_this_status
FROM #TABLE1 x
LEFT JOIN (
SELECT a.*
FROM #TABLE1_hist a
INNER JOIN (
SELECT id,
MIN(date_this_status) AS date_this_status
FROM #TABLE1_hist
GROUP BY id
) b
ON a.id = b.id
AND a.date_this_status = b.date_this_status
) y
ON x.id = y.id
SELECT id,
status,
date_this_status
FROM ( SELECT *
FROM Table1
UNION
SELECT *
from TABLE1_hist
) a
WHERE date_this_status = ( SELECT MIN(date_this_status)
FROM ( SELECT *
FROM Table1
UNION
SELECT *
from TABLE1_hist
) t
WHERE id = a.id
)
This is a bit ugly, but seems to work in MS SQL Server 2005.
You can do this with an exclusive self join. Join on the history table, and then another time on all earlier history entries. In the where statement, you specify that there are not allowed to be any earlier entries.
select t1.id,
isnull(hist.status, t1.status),
isnull(hist.date_this_status, t1.date_this_status)
from table1 t1
left join (
select h1.id, h1.status, h1.date_this_status
from table1_hist h1
left join table1_hist h2
on h2.id = h1.id
and h2.date_this_status < h1.date_this_status
where h2.date_this_status is null
) hist on hist.id = t1.id
A bit of a mind-binder, but fairly flexible and efficient!
This assumes there are no two history entries with the exact same date. If there are, write the self join like:
left join table1_hist h2
on h2.id = h1.id
and (
h2.date_this_status < h1.date_this_status
or (h2.date_this_status = h1.date_this_status and h2.id < h1.id)
)
If I understand the OP correctly, a given ID may appear in TABLE1 or TABLE1_HISTORY or both.
In your result set, you want back each distinct ID and the oldest status/date associated with that ID, regardless which table the oldest one happens to be in.
So, look in BOTH tables and return any record where there is no record in either table for it's ID that has a smaller date_this_status.
Try this:
SELECT ID, status, date_this_status FROM table1 ta WHERE
NOT EXISTS(SELECT null FROM table1 tb WHERE
tb.id = ta.id
AND tb.date_this_status < ta.date_this_status)
AND NOT EXISTS(SELECT null FROM table1_history tbh WHERE
tbh.id = ta.id
AND tbh.date_this_status < ta.date_this_status)
UNION ALL
SELECT ID, status, date_this_status FROM table1_history tah WHERE
NOT EXISTS(SELECT null FROM table1 tb WHERE
tb.id = tah.id
AND tb.date_this_status < tah.date_this_status)
AND NOT EXISTS(SELECT null FROM table1_history tbh WHERE
tbh.id = tah.id
AND tbh.date_this_status < tah.date_this_status)
Three underlying assumptions here:
Every ID you want back will have at least one record in at least one of the tables.
There won't be multiple records for the same ID in the same table with the same date_this_status value (can be mitigated by using DISTINCT)
There won't be records for the same ID in the other table with the same date_this_status value (can be mitigated by using UNION instead of UNION ALL)
There are two slight optimizations we can make:
If an ID has a record in TABLE1_HISTORY, it will always be older than the record in TABLE1 for that ID.
TABLE1 will never contain multiple records for the same ID (but the history table may).
So:
SELECT ID, status, date_this_status FROM table1 ta WHERE
NOT EXISTS(SELECT null FROM table1_history tbh WHERE
tbh.id = ta.id
)
UNION ALL
SELECT ID, status, date_this_status FROM table1_history tah WHERE
NOT EXISTS(SELECT null FROM table1_history tbh WHERE
tbh.id = tah.id
AND tbh.date_this_status < tah.date_this_status)
If that is the actual structure of your tables, you can't get a 100% accurate answer, the issue being that you can have 2 different statuses for the same (earliest) date for any given record and you would not know which one was entered first, because you don't have a primary key on the history table
Ignoring the "two tables" issues for a moment, I'd use the following logic...
SELECT
id, status, date
FROM
Table1_hist AS [data]
WHERE
[data].date = (SELECT MIN(date) FROM Table1_hist WHERE id = [data].id)
(EDIT: As per BlackTigerX's comment, this assumes no id can have more than one status with the same datetime.)
The simple way to extrapolate this to two tables is to use breitak67's answer. Replace all instances of "my_table" with subqueries that UNION the two tables together. A potential issue here is that of performance, as you may find that indexes become unusable.
One method of speeding this up could be to use implied knowledge:
1. The main table always has a record for each id.
2. The history table doesn't always have a record.
3. Any record in the history table is always 'older' than the one in main table.
SELECT
[main].id,
ISNULL([hist].status, [main].status),
ISNULL([hist].date, [main].date)
FROM
Table1 AS [main]
LEFT JOIN
(
SELECT
id, status, date
FROM
Table1_hist AS [data]
WHERE
[data].date = (SELECT MIN(date) FROM Table1_hist WHERE id = [data].id)
)
AS [hist]
ON [hist].id = [main].id
Find the oldest status for each id in the history table. (Can use its indexes)
LEFT JOIN that to the main table (which always has exactly one record for each id)
If [hist] contains a value, it's the older by definition
If the [hist] doesn't have a value, use the [main] value