How to get min value from set - sql

I have this table:
Profile_id Phase_id order
30087853 30021628 525
30087853 30021635 523
30087853 30021673 122
30087853 30021703 521
from the above I would like to get profile_id along with this phase_id, which has lowest order_num, so the outcome will be like:
Profile_id Phase_id order
30087853 30021673 122

You didn't specify your DBMS so this is standard SQL:
select profile_id, phase_id, "order"
from (
select profile_id, phase_id, "order",
row_number() over (partition by profile_id order by "order") as rn
from the_table
) t
where rn = 1;
Online example: http://rextester.com/MAUV44954

Without a sub-query or self-join you can use also this one:
SELECT Profile_id, MIN("order") as "order",
MIN(Phase_id) KEEP (DENSE_RANK FIRST ORDER BY "order") AS Phase_id
FROM your_table
GROUP BY Profile_id;

CREATE TABLE #table(Profile_id INT, Phase_id INT, _order INT)
INSERT INTO #table(Profile_id , Phase_id , _order )
SELECT 30087853,30021628,525 UNION ALL
SELECT 30087853,30021635,523 UNION ALL
SELECT 30087853,30021673,122 UNION ALL
SELECT 30087853,30021703,521
SELECT *
FROM #table T1
JOIN
(
SELECT Profile_id ProfileId, MIN(_order) [order]
FROM #table
GROUP BY Profile_id
) A ON T1.Profile_id = ProfileId AND T1._order = [order]

Related

Insert last not null value in temp table by date

I have this table for testing:
CREATE TABLE #ExchRates
(
[TimeId] int,
[CurrencyId] INT,
[ExchRate] DECIMAL(30,6)
)
INSERT INTO #ExchRates ([TimeId], [CurrencyId], [ExchRate])
VALUES
(
2017030500,
3,
6.142911
),
(
2017030600,
3,
6.152911
),
(
2017030700,
3,
NULL
),
(
2017030800,
3,
5.5
)
;
I want to insert values from this table in other table for one particular day(TimeId BETWEEN GETUTCDATE()-1 AND GETUTCDATE). Problem is when ExchRate is not set (NULL in table #ExchRate). In that case I want to use last known ExchRate for that currency. How can I solve this problem?
Try this-
SELECT * FROM(
SELECT *, ROW_NUMBER() OVER (ORDER BY TimeID DESC) RN
FROM #ExchRates
WHERE ExchRate IS NOT NULL
) A WHERE RN = 1
If you have more than one currency in the table, you can do this following -
SELECT * FROM(
SELECT *, ROW_NUMBER() OVER (PARTITION BY CurrencyId ORDER BY TimeID DESC) RN
FROM #ExchRates
WHERE ExchRate IS NOT NULL
) A WHERE RN = 1
for the case of null you can use row_number() for getting the last value
select * from (select *,row_number() over(partition by CurrencyId order by TimeId desc) rn
from #ExchRates
) a where a.rn=1
Here's your query.
insert into Table2 ([TimeId], [CurrencyId], [ExchRate])
select ([TimeId], [CurrencyId], [ExchRate]),
isnull([ExchRate], (select top 1 [ExchRate] from #ExchRates order by [TimeId] desc)) from #ExchRates
Use ROW_NUMBER() to get the last record you want :
WITH CTE AS (
SELECT *,ROW_NUMBER() OVER (PARTITION BY CurrencyId ORDER BY TimeId DESC) rn
FROM #ExchRates )
SELECT
*
FROM CTE
WHERE rn = 1;

Select unique field

I have this table:
TableA
----------------
ID (pk) Name
1 A
2 B
3 C
4 A
5 D
6 A
7 B
8 A
9 D
10 C
....
I need to randomly extract with a SELECT TOP 5 ID, Name FROM TableA
with Name that must be unique within the 5 records.
I'm trying :
;WITH group
AS
(
SELECT ID, Name,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY NewId()) rn
FROM TableA
)
SELECT ID, Name
FROM group
WHERE rn = 1
but every time I have quite the same results.
I need to select between all the values for ID at random, assuring that Name will always be different for each record.
I hope the problem is understandable. Any ideas?
Found a solution. It seems to work!
;WITH group
AS (
SELECT ID, Name, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY NewId()) rn FROM TableA )
SELECT top 5 ID, Name, NewId() [NewId]
FROM group
WHERE rn = 1
ORDER BY [newid]
Perhaps the problem is that although newid() is random, it may tend to be sequential. Does this fix the problem?
WITH g as (
SELECT ID, Name,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY RAND(CHECKSUM(NewId()))) as rn
FROM TableA
)
SELECT ID, Name
FROM g
WHERE rn = 1;
CREATE TABLE #test(ID INT ,Name VARCHAR(1)) INSERT INTO #test(ID ,Name )
SELECT 1,'A' UNION ALL SELECT 2,'B' UNION ALL SELECT 3,'C' UNION ALL
SELECT 4,'A' UNION ALL SELECT 5,'D'UNION ALL SELECT 6,'A' UNION ALL
SELECT 7,'B' UNION ALL SELECT 8,'A'UNION ALL SELECT 9,'D' UNION ALL
SELECT 10,'C'
SELECT T1.ID ,T1.Name FROM #test T1
JOIN ( SELECT TOP 5 Name FROM #test T2 ORDER BY NEWID()
) A ON T1.Name = A.Name ORDER BY A.Name
;WITH group
AS
(
SELECT ID, Name,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY NewId()) rn
FROM TableA
)
SELECT top 5 ID, Name, NewId() [NewId]
FROM group
WHERE rn = 1
ORDER BY [newid]

Get the maximum values of column B per each distinct value of column A sql

I have this table:
I am trying to pull all records from this table for the max value in the DIST_NO column for every distinct ID in the left most column, but I still want to pull every record for each ID in which there are different Product_ID's as well.
I tried partitioning and using row_number, but I am having trouble at the moment.
Here are my desired results:
This is what my code looks like currently:
select *
from
(SELECT *,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DIST_NO DESC) RN
FROM Table) V
WHERE RN<=3
you want the max(DIST_NO) for each ID, product_ID?
If so, you can:
SELECT
ID, product_ID, max(DIST_NO)
from table
group by ID, product_ID
If you want the detail rows related to the max row, you just need to join it back to your table:
Select
t.ID, max_dist_no, TRANSaction_ID , LINE_NO , PRODUCT_ID
from
table t inner join
(SELECT
ID, max(DIST_NO) as max_dist_no
from table
group by ID) mx on
t.ID = mx.ID and
t.DIST_NO = max_DIST_NO
Try
SELECT MT.ID
, MT.DIST_NO
, MT.TRANS_ID
, MT.LINE_NO
, MT.PRODUCT_ID
FROM MYTABLE MT
INNER JOIN (
SELECT T.ID, MAX(T.DIST_NO) as DIST_NO FROM MYTABLE T
GROUP BY T.ID
) MAX_MT ON MT.Id = MAX_MT.ID AND MT.DIST_NO = MAX_MT.DIST_NO
The sub query returns each combination of ID and Max value of DIST_NO:
SELECT T.ID, MAX(T.DIST_NO) as DIST_NO FROM MYTABLE T
GROUP BY T.ID
Joining this back to your original table will basically filter your original data-set by only these combinations of values.
Tested on PostgreSQL:
WITH t1 AS (
SELECT id, product_id, MAX(dist_no) AS dist_no
FROM test
GROUP BY 1,2)
SELECT t1.id, t1.dist_no, t2.trans_id, t2.line_no, t1.product_id
FROM test t2, t1
WHERE t1.id=t2.id AND t1.product_id=t2.product_id AND t1.dist_no=t2.dist_no
Use rank() or dense_rank():
select t.*
from (SELECT t.*
RANK() OVER (PARTITION BY ID ORDER BY DIST_NO DESC) as seqnum
FROM Table t
) t
WHERE seqnum = 1;
This is almost a literal translation of your request:
I am trying to pull all records from this table for the max value in
the DIST_NO column for every distinct ID in the left most column.
you can try something like this one :). (But is your result correct? I think there is little mistake in TRANS_ID...)
DECLARE #ExampleTable TABLE
(ID INT,
DIST_NO INT,
TRANS_ID INT,
LINE_NO INT,
PRODUCT_ID INT)
INSERT INTO #ExampleTable
( ID, DIST_NO, TRANS_ID,LINE_NO, PRODUCT_ID )
VALUES ( 102657, 1, 1105365, 1, 109119 ),
( 102657, 1, 1105366, 2, 109114 ),
( 102657, 2, 1105365, 1, 109119 ),
( 102657, 2, 1105366, 2, 109114 ),
( 104371, 1, 1190538, 1, 110981 ),
( 104371, 2, 1190538, 1, 110981 )
;WITH CTE AS ( SELECT DISTINCT ID, LINE_NO
FROM #ExampleTable)
SELECT a.ID,
x.DIST_NO,
x.TRANS_ID,
x.LINE_NO,
x.PRODUCT_ID
FROM CTE a
CROSS APPLY (SELECT TOP 1 *
FROM #ExampleTable f
WHERE a.ID = f.ID AND
a.LINE_NO = f. LINE_NO
ORDER BY DIST_NO DESC) x

Get Second duplicate Record

I am getting after doing joins as ::
CompanyID EmpID Emp_no Location
-------------------- -------------------- ------------- -------------
1 24 100543 First.png
1 24 100543 Second.png
I want to select second Record i.e. Second.png by using CASE WHEN in select query.
Check this out.
declare #t table(CompanyID int, empid int, emp_no varchar(50), location varchar(100))
insert into #t values (1,24,100543,'First.png'),(1,24,100543,'Second.png'),(1,25,100544,'Second.png'),(1,25,100544,'First.png')
select * from
(
select
ROW_NUMBER() over(partition by companyid, empid order by companyid, empid ) rowno, *
from
#t
) a where rowno = 2 --and empid = 24 --here you can give empid to get particular employee detail
In case you want to get multiple empid's second entry in single select statement.
declare #t table(CompanyID int, empid int, emp_no varchar(50), location varchar(100))
insert into #t values (1,24,100543,'First.png'),(1,24,100543,'Second.png'),(1,25,100544,'Second.png'),(1,25,100544,'First.png')
,(1,26,100545,'First.png')
;with cte as
(
select
*
from
(
select
ROW_NUMBER() over(partition by empid order by empid ) rowno, *
from
#t
) a
),
cte1 as (
select
*,
ROW_NUMBER() OVER(PARTITION BY empid ORDER BY rowno DESC) as RN
from cte
)
select * from cte1 where rn = 1
You can write as:
;WITH CTE as
(
SELECT ROW_NUMBER() OVER ( PARTITION BY CompanyID,EmpID,Emp_no ORDER BY (SELECT 1))
AS rownum,CompanyID,EmpID,Emp_no,Location
FROM (SELECT * FROM #Test ) AS T
),CTE1 as
(
SELECT MAX(rownum) AS maxrownum,
CompanyID,
EmpID,
Emp_no
FROM CTE
GROUP BY CompanyID,EmpID,Emp_no
)
SELECT T.CompanyID,T.EmpID,T.Emp_no,T.Location
FROM CTE T
JOIN CTE1 T1 ON T.CompanyID = T1.CompanyID
AND T.EmpID = T1.EmpID
AND T.Emp_no = T1.Emp_no
AND T.rownum = T1.maxrownum
Explanation:
As there's no column like primary key through which we can identify
which row comes first you can write SELECT 1 in partition window.
Once you get rownumber for each combination of CompanyID,EmpID and Emp_no you can use second CTE to get the maxrow for each
combination
Just collect the data from the table for all rows with maxrownumbers
Hope this helps:)

SQL cross apply

I have a SQL table which contains audit information:
GroupId AuditDate ID FirstName LastName
1 01/06/2011 123 Michael Jackson
1 01/09/2010 123 M J
1 01/06/2009 123 Mike J
and trying show the differences between the audit records:
GroupId AuditDate ID Attribute From To
1 01/06/2011 123 FirstName M Michael
1 01/06/2011 123 LastName J Jackson
1 01/09/2010 123 FirstName Mike M
1 01/06/2009 123 FirstName NULL Mike
1 01/06/2009 123 LastName NULL J
I am using the following SQL query:
WITH result AS (
SELECT [Current].Id,
[Current].GroupId,
[Current].AuditDate,
[Current].FirstName,
[Current].LastName
Previous.FirstName AS PFirstName,
Previous.LastName AS PLastName,
FROM
(SELECT
*, ROW_NUMBER() OVER(PARTITION BY GroupId ORDER BY AuditDate ASC) AS RowNumber
FROM
AuditTable
WHERE
Id = #ID
) AS [Current]
LEFT JOIN
(SELECT
*, ROW_NUMBER() OVER(PARTITION BY GroupId ORDER BY AuditDate ASC) AS RowNumber
FROM
AuditTable
WHERE
Id = #ID
) AS [Previous]
ON
[Current].RowNumber = [Previous].RowNumber + 1
)
SELECT r.Id,r.GroupId, r.AuditDate
x.Attribute,
x.[From],
x.[To]
FROM result r
CROSS APPLY
(
VALUES
('FirstName', t.FirstName, t.PFirstName),
('LastName', t.LastName, t.PLastName),
) x (Attribute, [To], [From])
where
ISNULL(x.[From],'') <> ISNULL(x.[To],'')
ORDER BY r.AuditDate asc;
Is it possible to merge two select queries to improve the performance?
Try this query
WITH result AS (
SELECT Id,
GroupId,
AuditDate,
FirstName,
LastName,
ROW_NUMBER() OVER(PARTITION BY GroupId ORDER BY AuditDate ASC) AS RowNumber
FROM AuditTable
WHERE Id = #ID
)
SELECT r.Id,r.GroupId, r.AuditDate,
x.Attribute,
x.[From],
x.[To]
FROM result r LEFT JOIN result r2 ON r.RowNumber = r2.RowNumber + 1
CROSS APPLY (
VALUES ('FirstName', r.FirstName, r2.FirstName),
('LastName', r.LastName, r2.LastName)
) x (Attribute, [To], [From])
WHERE ISNULL(x.[From],'') <> ISNULL(x.[To],'')
ORDER BY r.AuditDate ASC;
Demo on SQLFiddle
You can eliminate both subqueries entirely by using lag():
WITH result AS (
SELECT Id,
GroupId,
AuditDate,
FirstName,
LastName,
lag(FirstName) over (PARTITION BY GroupId ORDER BY AuditDate ASC)
AS PFirstName,
lag(LastName) over (PARTITION BY GroupId ORDER BY AuditDate ASC)
AS PLastName
FROM AuditTable
WHERE Id = #ID
)
...
Here is the relevant documentation.
Update: However, this is only available in SQL Server 2012, unfortunately. If you have an earlier version, you will need some sort of self join.
If you can't use lag(), you should at least be able to reduce your code from 3 queries to 2: include the row number in your first select statement, and left join one subquery to it rather than having two subqueries. I'm not sure whether this way or Chris Moutray's way would be faster.
WITH result AS (
SELECT ROW_NUMBER() OVER(PARTITION BY GroupId ORDER BY AuditDate ASC) AS RowNumber
[Current].Id,
[Current].GroupId,
[Current].AuditDate,
[Current].FirstName,
[Current].LastName
[Previous].FirstName AS PFirstName,
[Previous].LastName AS PLastName,
FROM AuditTable as [Current]
LEFT JOIN
(SELECT
*, ROW_NUMBER() OVER(PARTITION BY GroupId ORDER BY AuditDate ASC) AS RowNumber
FROM
AuditTable
WHERE
Id = #ID
) AS [Previous]
ON
[Current].RowNumber = [Previous].RowNumber + 1
)
You can use LAG in SQL Server 2012. I've used UNION ALL here to unpivot columns into rows.
Depending on how you filter and what your group level is, add/modify the PARTITION BY
DECLARE #foo TABLE (GroupId tinyint, AuditDate date, ID tinyint, FirstName varchar(100), LastName varchar(100));
INSERT #foo VALUES (1, '20110601', 123, 'Michael', 'Jackson'), (1, '20100901', 123, 'M', 'J'), (1, '20090601', 123, 'Mike', 'J');
SELECT
X.GroupId, X.AuditDate, X.ID, X.[From], X.[To]
FROM
(
SELECT
F.GroupId, F.AuditDate, F.ID, 'FirstName' AS Attribute, LAG(F.FirstName) OVER (/*PARTITION BY GroupId, ID*/ ORDER BY AuditDate) AS [From], F.FirstName AS [To]
FROM
#foo F
UNION ALL
SELECT
F.GroupId, F.AuditDate, F.ID, 'LastName' AS Attribute, LAG(F.LastName) OVER (/*PARTITION BY GroupId, ID*/ ORDER BY AuditDate) AS [From], F.LastName AS [To]
FROM
#foo F
) X
WHERE
ISNULL(X.[From], '') <> ISNULL(X.[To], '')
ORDER BY
X.AuditDate DESC, X.Attribute