Find max value from coalesce function - sql

This is my query:
declare #t table (date1 date,date2 date,date3 date)
insert into #t values ('2019-01-01','2019-01-20','2019-02-10')
insert into #t values (null,null,'2019-02-01')
insert into #t values (null,'2019-02-01','2019-02-02')
My expected output is:
2019-02-10
2019-02-01
2019-02-02
I tried to use coalesce like :
select coalesce(date1,date2,date3) as maxdate from #t
I know coalesce returns first not null value. So what I can do to get my desired result.

This will do the trick.
Basically you transform every row in a data-set, using VALUES clause, and then just get the MAX value.
SELECT (
SELECT MAX(LastUpdateDate)
FROM (VALUES (date1),(date2),(date3)) AS UpdateDate(LastUpdateDate)) AS LastUpdateDate
FROM #t

coalesce() has nothing to do with this. Unfortunately, SQL Server does not support greatest(). But you can use apply:
select t.*, m.max_date
from #t t cross apply
(select max(dte) as max_date
from (values (t.date1), (t.date2), (t.date3)) v(dte)
) m;
The max() ignores NULL values, so this does what you expect.
Here is a db<>fiddle.

Personally I would normalise your data, by unpivoting it, and then getting the MAX in the group. This does, however, require you have some kind of column to identify the row (I use an IDENTITY in this example):
DECLARE #t table (id int IDENTITY,
date1 date,
date2 date,
date3 date);
INSERT INTO #t
VALUES ('2019-01-01', '2019-01-20', '2019-02-10');
INSERT INTO #t
VALUES (NULL, NULL, '2019-02-01');
INSERT INTO #t
VALUES (NULL, '2019-02-01', '2019-02-02');
SELECT MAX([date])
FROM #t t
CROSS APPLY (VALUES(t.date1),(date2),(t.date3))V([date])
GROUP BY t.id;

Related

how to pick only last string

I have data like this I have seen functions and Substring and LEFT ,RIGHT also
but it is not serving my purpose
declare #t table (val varchar(50))
INSERT INTO #t(val)values ('E-001GHDEM120ENDORSEMENT'),
('E-001GHDEM120Renewal'),
('E-001GHDEM120Adjustment'),
('E-001GHDEM120ENDORSEMENT')
select * from #t
output
ENDORSEMENT
Renewal
Adjustment
ENDORSEMENT
I need to use that statement in where condition to filter records
Try this select
DECLARE #t TABLE
(
val VARCHAR(50)
);
INSERT INTO #t
(val
)
VALUES
('E-001GHDEM120ENDORSEMENT'
),
('E-001GHDEM120Renewal'
),
('E-001GHDEM120Adjustment'
),
('E-001GHDEM120ENDORSEMENT'
);
SELECT REVERSE(SUBSTRING(REVERSE(val), 0, PATINDEX('%[^a-zA-Z]%', REVERSE(val)))) AS val
FROM #t;
Try This. From your example here is what i understood.
select right(val,patindex('%[0-9]%', reverse(val))-1)
from #t

sorting SQL with substring on string

i have the data like this:
CODE_VD
N_10_19_xxx
N_0_3_xxx
N_121_131_xxx
N_100_120_xxx
N_80_90_xxx
N_20_29_xxx
as you can see i need to sort just the first number after N_,i don't know how can i get this number.
i have tried with susbsting(CODE_VD,2,3) but not exactly what i expected.
i want to get this:
CODE_VD
N_0_3_xxx
N_10_19_xxx
N_20_29_xxx
N_80_90_xxx
N_100_120_xxx
N_121_131_xxx
how can i do that ?
DECLARE #MyTable TABLE
(
CODE_VD VARCHAR(20)
)
INSERT INTO #MyTable
( CODE_VD )
VALUES
('N_10_19_xxx'),
('N_0_3_xxx'),
('N_121_131_xxx'),
('N_100_120_xxx'),
('N_80_90_xxx'),
('N_20_29_xxx');
SELECT * FROM
(
SELECT
*,
CONVERT(INT,
SUBSTRING(mt.CODE_VD,
3,
CHARINDEX('_', mt.CODE_VD, 3) - 3)) ConvCol
FROM #MyTable mt
) mt
ORDER BY mt.ConvCol
I converted to int to get the sort to work correctly, because 100 > 20
SELECT SUBSTRING(CODE_VD,3, CHARINDEX('_',CODE_VD, 3)-3)
declare #t Table (CODE_VD VARCHAR(MAX))
INSERT INTO #t (CODE_VD)VALUES ('N_10_19_xxx')
INSERT INTO #t (CODE_VD)VALUES ('N_0_3_xxx')
INSERT INTO #t (CODE_VD)VALUES ('N_121_131_xxx')
INSERT INTO #t (CODE_VD)VALUES ('N_100_120_xxx')
;WITH
sorted
AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY SUBSTRING(CODE_VD,3, CHARINDEX('_',CODE_VD, 3)-3) ORDER BY CODE_VD) AS sequence_id
FROM
#t
)
SELECT
CODE_VD
FROM
sorted
WHERE
sequence_id = 1

Is there a way to return more than 1 row in select without using existing tables

Simple question, just out of curiosity.
For example select 1,2,3 that will show table with one column and three rows.
Something like this: select values(1),(2),(3)
*with one select statement
An example for my comment in your post.
DECLARE #TABLE TABLE (ONE INT, TWO INT, THREE INT)
INSERT INTO #TABLE VALUES (1,2,3)
SELECT UP.COL, UP.VALUE
FROM #TABLE
UNPIVOT (VALUE FOR COL IN (ONE,TWO,THREE)) UP
Query:
DECLARE #t TABLE (i1 INT, i2 INT, i3 INT)
INSERT INTO #t VALUES (1, 2, 3)
SELECT t.*
FROM #t
CROSS APPLY (
VALUES(i1), (i2), (i3)
) t(value)
Output:
value
-----------
1
2
3
Additional info:
http://blog.devart.com/is-unpivot-the-best-way-for-converting-columns-into-rows.html
As it appears there is a simple code that I've been searching for:
select n from (values (1),(2),(3)) D(c);

Get records with more than one value and at least one of them is zero

Create table #Tbl
(
ID int not null,
Keyword nvarchar(max)
)
Insert into #Tbl Values ('0','Cryptography')
Insert into #Tbl Values ('1','Cryptography')
Insert into #Tbl Values ('4','Cryptography')
Insert into #Tbl Values ('0','SQL')
Insert into #Tbl Values ('0','SQL')
Insert into #Tbl Values ('3','Cloud Computing')
Insert into #Tbl Values ('6','Recursion')
Insert into #Tbl Values ('8','Recursion')
Insert into #Tbl Values ('0','Universe')
Insert into #Tbl Values ('0','Universe')
Insert into #Tbl Values ('7','Universe')
I need to get the titles which has more than one ID and at least one of the ID is zero.
So the expected result will be:
Cryptography
Universe
I tried below query but not able to add "at least one id is zero" condition
select Keyword,COUNT(distinct id) from #Tbl
group by Keyword
having COUNT(distinct id)>1
How can I proceed here ? Thanks for your help.
Assuming your IDs start from 0, the below should work
select Keyword,COUNT(distinct id) from #Tbl
group by Keyword
having COUNT(distinct id)>1 and MIN(id) = 0
There are many ways to do this, one example:
SELECT DISTINCT Keyword
FROM #Tbl T
WHERE EXISTS (SELECT 1 FROM #Tbl WHERE Keyword = T.Keyword
AND ID = 0)
AND EXISTS (SELECT 1 FROM #Tbl WHERE Keyword = T.Keyword
AND ID != 0)
Here is a sqlfiddle with a demo.
This should do it:
SELECT Keyword
FROM #Tbl
WHERE Keyword IN (SELECT DISTINCT Keyword FROM #Tbl WHERE ID = 0)
GROUP BY Keyword
HAVING COUNT(DISTINCT id) > 1
Here's yet another approach:
SELECT Keyword, COUNT(DISTINCT ID)
FROM #Tbl
GROUP BY Keyword
HAVING COUNT(DISTINCT ID) > ALL (SELECT COUNT(DISTINCT NULLIF(ID, 0)) UNION ALL SELECT 1)
;

SQL Server Simple Group by query

I have a simple problem , Although i believe its simple , am not able to figure out the same.
Consider i have the below table with exactly same data as given below :
CREATE TABLE #temp
(
link varchar(255),
number INT,
fname varchar(255)
)
insert into #temp VALUES ('abc',1,'f1')
insert into #temp VALUES ('abc',2,'f2')
insert into #temp VALUES ('abc',3,'f3')
insert into #temp VALUES ('abc',4,'f6')
insert into #temp VALUES ('abc',10,'f100')
insert into #temp VALUES ('abe',-1,'f0')
insert into #temp VALUES ('abe',1,'f1')
insert into #temp VALUES ('abe',2,'f2')
insert into #temp VALUES ('abe',3,'f3')
insert into #temp VALUES ('abe',4,'f6')
insert into #temp VALUES ('abe',20,'f200')
insert into #temp VALUES ('cbe',-1,'f0')
insert into #temp VALUES ('cbe',1,'f1')
insert into #temp VALUES ('cbe',2,'f2')
insert into #temp VALUES ('cbe',3,'f3')
Now for a given link , i need to get the max 'number' and the corresponding 'fname' which has the max 'number' for the given 'link'.
1)Ex : if link is 'abc' , output should be
abc, 10, f100
2)Ex : if link if 'abe' , Output should be
abe, 20, f200
3)Now link can be also given as a pattern , like (link like 'ab%') , so output should be
abc, 10, f100
abe, 20, f200
4)if (link like 'cb%') , so output should be
cbe, 3, f3
Any help in writing this group by query. I have a solution using CAST and string concat like below , but that seems to be in-efficient.
select link,number,fname from #temp
where link like 'ab%' and link+'_'+CAST(number AS varchar(255))
in (select link+'_'+CAST(MAX(number) AS varchar(255)) from #temp
group by link)
Thanks..
Using a self join:
SELECT x.link,
x.number,
x.fname
FROM #temp x
JOIN (SELECT t.link,
MAX(t.number) AS max_number
FROM #temp t
GROUP BY t.link) y ON y.link = x.link
AND y.max_number = x.number
Using a CTE and ROW_NUMBER (SQL Server 2005+):
WITH cte AS (
SELECT x.link,
x.number,
x.fname,
ROW_NUMBER() OVER(PARTITION BY x.link
ORDER BY x.number DESC) rank
FROM #temp x)
SELECT c.link,
c.number,
c.fname
FROM cte c
WHERE c.rank = 1