SQL - Getting Most Recent Date From Multiple Columns - sql

Assume a rowset containing the following
EntryID Name DateModified DateDeleted
-----------------------------------------------
1 Name1 1/2/2003 NULL
2 Name1 1/3/2005 1/5/2008
3 Name1 1/3/2006 NULL
4 Name1 NULL NULL
5 Name1 3/5/2008 NULL
Clarification:
I need a single value - the largest non-null date from BOTH columns. So the largest of all ten cells in this case.

SELECT MAX(CASE WHEN (DateDeleted IS NULL OR DateModified > DateDeleted)
THEN DateModified ELSE DateDeleted END) AS MaxDate
FROM Table

For MySQL, Postgres or Oracle, use the GREATEST function:
SELECT GREATEST(ISNULL(t.datemodified, '1900-01-01 00:00:00'),
ISNULL(t.datedeleted, '1900-01-01 00:00:00'))
FROM TABLE t
Both Oracle and MySQL will return NULL if a NULL is provided. The example uses MySQL null handling - update accordingly for the appropriate database.
A database agnostic alternative is:
SELECT z.entryid,
MAX(z.dt)
FROM (SELECT x.entryid,
x.datemodified AS dt
FROM TABLE x
UNION ALL
SELECT y.entryid
y.datedeleted AS dt
FROM TABLE y) z
GROUP BY z.entryid

As a general solution, you could try something like this:
select max(date_col)
from(
select max(date_col1) AS date_col from some_table
union
select max(date_col2) AS date_col from some_table
union
select max(date_col3) AS date_col from some_table
...
)
There might be easier ways, depending on what database you're using.

How about;
SELECT MAX(MX) FROM (
SELECT MAX(DateModified) AS MX FROM Tbl
UNION
SELECT MAX(DateDeleted) FROM Tbl
) T

The answer depends on what you really want. If you simply want the most recent of the two date values then you can do:
Select Max(DateModified), Max(DateDeleted)
From Table
If you are asking for the largest value from either column, then you can simply do:
Select Case
When Max(DateModified) > Max(DateDeleted) Then Max(DateModified)
Else Max(DateDeleted)
End As MaxOfEitherValue
From Table

The above are all valid answers;
But I'm Not sure if this would work?
select IsNull((
select MAX(DateModified)
from table
)
,
(
select MAX(DateDeleted)
from table
)
) as MaxOfEitherValue
from table
Edit 1:
Whilst in the shower this morning, I had another solution:
Solution 2:
select MAX(v) from (
select MAX(DateModified) as v from table
union all
select MAX(DateDeleted) as v from table
) as SubTable
Edit 3:
Damn it, just spotted this is the same solution as Alex k. sigh...

How to find the Latest Date from the columns from Multiple tables
e.g. if the Firstname is in Table1, Address is in Table2, Phone is in Table3:
When you are using with main SELECT statement while selecting other columns it is best written as :
SELECT Firstname
,Lastname
,Address
,PhoneNumber
,
,(SELECT max(T.date_col) from(select max(date_col1) AS date_col from Table1 Where ..
union
select max(date_col2) AS date_col from Table2 Where..
union
select max(date_col3) AS date_col from Table3 Where..
) AS T
) AS Last_Updated_Date
FROM Table T1
LEFT JOIN Table T2 ON T1.Common_Column=T2.Common_Column
LEFTJOIN Table T3 ON T1.Common_Column=T3.Common_Column

Related

PostgreSQL query to list all values of a column that are common between tables

I have a column named endate(its values are dates) present in five tables, straddle0, straddle1, straddle2, straddle3 and straddle4. My assumption regarding the data is that, one table's endate values are not present in any of the other mentioned tables(can be repeated in the same table though). But to confirm, I want to list all the endate values that might be present in multiple tables (like 01-01-2017 is present in straddle0 and also in straddle4 or 02-02-2017 is present in straddle1 and also in straddle3 and straddle5).
What is the PostgreSQL query for the same?
I would use UNION ALL and a GROUP BY/HAVING:
Schema (PostgreSQL v13)
CREATE TABLE t1 (
enddate date
);
CREATE TABLE t2 (
enddate date
);
CREATE TABLE t3 (
enddate date
);
INSERT INTO t1
VALUES (CURRENT_DATE), (CURRENT_DATE+1);
INSERT INTO t2
VALUES (CURRENT_DATE), (CURRENT_DATE+2), (CURRENT_DATE+2);
INSERT INTO t3
VALUES (CURRENT_DATE+2), (CURRENT_DATE+3);
Query #1
WITH all_dates AS (
SELECT 't1' AS table_name, enddate
FROM t1
UNION ALL
SELECT 't2' AS table_name, enddate
FROM t2
UNION ALL
SELECT 't3' AS table_name, enddate
FROM t3
)
SELECT enddate, ARRAY_AGG(DISTINCT table_name) AS appears_in
FROM all_dates
GROUP BY 1
HAVING COUNT(DISTINCT table_name) > 1
ORDER BY 1;
enddate
appears_in
2022-05-07T00:00:00.000Z
t1,t2
2022-05-09T00:00:00.000Z
t2,t3
View on DB Fiddle
Not sure what format you want the result in. I made two scripts - a simple one and a more detailed one. Perhaps this is what you need
Here is dbfiddle
with data(dt, t) as (
select distinct endate, 0 from straddle0 union all
select distinct endate, 1 from straddle1 union all
select distinct endate, 2 from straddle2 union all
select distinct endate, 3 from straddle3 union all
select distinct endate, 4 from straddle4
)
select dt, min(t) as t from data group by dt having count(*) = 1;

Table with 2 dates I want a single list of unique dates

Say for example I have a table with date start and date end
Item 1 10/2/2019 12/2/2019
Item 2 10/2/2019 15/2/2019.
I wish to have a result of
Item 1 10/2/2019
Item 2 12/2/2019
Item 3 15/2/2019
In a single column that I can use for further queries
Can’t think of how to get the desired result
See above
Here is what you asked for if you are using Oracle:
select 'Item ' || ROW_NUMBER() OVER(
ORDER BY date_row
) row_num
, date_row
from (
select start_date as Date_row from table1
union
select end_date as Date_row from table1);
And here is the DEMO
Here is what you asked for if you are using MySQL:
select concat("Item ", ROW_NUMBER() OVER(ORDER BY date_row)) as Item
, date_row
from (
select start_date as Date_row from table1 as t1
union
select end_date as Date_row from table1 as t2
) as test;
And here is the DEMO
Here is what you asked for if you are using Postgres:
select 'Item ' || ROW_NUMBER() OVER(
ORDER BY date_row
) row_num
, date_row
from (
select start_date as Date_row from table1 as t1
union
select end_date as Date_row from table1 as t2) as t3;
And here is the DEMO
Probably this:
SELECT 'startdate' as datekind, startdate
FROM table
UNION
SELECT 'enddate', enddate
FROM table
The kind is optional but I added it in to demo how you would retain knowledge of whether a date was start or end. You can add other columns like ID in in the same way
If you don't want to squish duplicates add the word ALL after UNION
NOTE - the presence of the kind column will influence whether a date is deemed a duplicate of another row or not. This query can still produce repeated dates if one is a start and the other an end. If this is unacceptable, remove the dateline column (and accept that you won't know what they are)
If we're generating a unique list of dates and the lowest item associated:
SELECT x.d, min(x.item) as i
FROM(
SELECT startdate as d, item FROM table
UNION ALL
SELECT enddate, item FROM table
) x
GROUP BY x.d

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.

Counting the rows of a column where the value of a different column is 1

I am using a select count distinct to count the number of records in a column. However, I only want to count the records where the value of a different column is 1.
So my table looks a bit like this:
Name------Type
abc---------1
def----------2
ghi----------2
jkl-----------1
mno--------1
and I want the query only to count abc, jkl and mno and thus return '3'.
I wasn't able to do this with the CASE function, because this only seems to work with conditions in the same column.
EDIT: Sorry, I should have added, I want to make a query that counts both types.
So the result should look more like:
1---3
2---2
SELECT COUNT(*)
FROM dbo.[table name]
WHERE [type] = 1;
If you want to return the counts by type:
SELECT [type], COUNT(*)
FROM dbo.[table name]
GROUP BY [type]
ORDER BY [type];
You should avoid using keywords like type as column names - you can avoid a lot of square brackets if you use a more specific, non-reserved word.
I think you'll want (assuming that you wouldn't want to count ('abc',1) twice if it is in your table twice):
select count(distinct name)
from mytable
where type = 1
EDIT: for getting all types
select type, count(distinct name)
from mytable
group by type
order by type
select count(1) from tbl where type = 1
;WITH MyTable (Name, [Type]) AS
(
SELECT 'abc', 1
UNION
SELECT 'def', 2
UNION
SELECT 'ghi', 2
UNION
SELECT 'jkl', 1
UNION
SELECT 'mno', 1
)
SELECT COUNT( DISTINCT Name)
FROM MyTable
WHERE [Type] = 1

Single SQL SELECT Returning multiple rows from one table row

We have a table which is of the form:
ID,Value1,Value2,Value3
1,2,3,4
We need to transform this into.
ID,Name,Value
1,'Value1',2
1,'Value2',3
1,'Value3',4
Is there a clever way of doing this in one SELECT statement (i.e without UNIONs)? The column names Value1,Value2 and Value3 are fixed and constant.
The database is oracle 9i.
Give a union a shot.
select ID, 'Value1' as Name, Value1 as Value from table_name union all
select ID, 'Value2', Value2 as Value from table_name union all
select ID, 'Value3', Value3 as Value from table_name
order by ID, Name
using union all means that the server won't perform a distinct (which is implicit in union operations). It shouldn't make any difference with the data (since your ID's should HOPEFULLY be different), but it might speed it up a bit.
This works on Oracle 10g:
select id, 'Value' || n as name,
case n when 1 then value1 when 2 then value2 when 3 then value3 end as value
from (select rownum n
from (select 1 from dual connect by level <= 3)) ofs, t
I think Oracle 9i had recursive queries? Anyway, I'm pretty sure it has CASE support, so even if it doesn't have recursive queries, you can just do "(select 1 from dual union all select 2 from dual union all select 3 from dual) ofs" instead. Abusing recursive queries is a bit more general- for Oracle. (Using unions to generate rows is portable to other DBs, though)
You can do it like this, but it's not pretty:
SELECT id,'Value 1' AS name,value1 AS value FROM mytable
UNION
SELECT id,'Value 2' AS name,value2 AS value FROM mytable
UNION
SELECT id,'Value 3' AS name,value3 AS value FROM mytable
Unioning three select statements should do the trick:
SELECT ID, 'Value1', Value1 AS Value
FROM TABLE
UNION
SELECT ID, 'Value2', Value2 AS Value
FROM TABLE
UNION
SELECT ID, 'Value3', Value3 AS Value
FROM TABLE
If you're using SQL Server 2005+ then you can use UNPIVOT
CREATE TABLE #tmp ( ID int, Value1 int, Value2 int, Value3 int)
INSERT INTO #tmp (ID, Value1, Value2, Value3) VALUES (1, 2, 3, 4)
SELECT
*
FROM
#tmp
SELECT
*
FROM
#tmp
UNPIVOT
(
[Value] FOR [Name] IN (Value1, Value2, Value3)
) uPIVOT
DROP TABLE #tmp
A UNION ALL, as others have suggested, is probably your best bet in SQL. You might also want to consider handling this in the front end depending on what your specific requirements are.
CTE syntax may be different for Oracle (I ran it in Teradata), but I only used CTE to provide test data, those 1 2 3 and 4. You can use temp table instead. The actual select statement is plain vanilla SQL and it will on any relational database.
For Sql Server, consider UNPIVOT as an alternative to UNION:
SELECT id, value, colname
FROM #temp t
UNPIVOT (Value FOR ColName IN (value1,value2,value3)) as X
This will return the column name as well. I'm unsure what the X is used for, but you can't leave it out.
Try this:
CTE creates a temp table with 4 values. You can run this as is in any database.
with TEST_CTE (ID) as
(select * from (select '1' as a) as aa union all
select * from (select '2' as b) as bb union all
select * from (select '3' as c) as cc union all
select * from (select '4' as d) as dd )
select a.ID, 'Value'|| a.ID, b.ID
from TEST_CTE a, TEST_CTE b
where b.ID = (select min(c.ID) from TEST_CTE c where c.ID > a.ID)
Here is the result set:
1 Value1 2
2 Value2 3
3 Value3 4
Enjoy!
Some afterthoughts.
^^^ CTE syntax may be different in Oracle. I could only run it in Teradata. You can substitute it with temp table or fix the syntax to make it Oracle compatible. The select statement is plain vanilla SQL that will work on any database.
^^^ Another thing to note. If ID field is numeric, you might need to cast it into CHAR in order to concatenate it with "Value".