sql group by and max and other values - sql

i have a table that contains:
itemid inventdimid datephysical transrefid
10001 123 2015-01-02 300002
10002 123 2015-01-03 3566
10001 123 2015-02-05 55555
10002 124 2015-02-01 4545
The result i want
itemid inventdimid datephysical transrefid
10001 123 2015-02-05 555
10002 123 2015-01-03 3566
10002 124 2015-02-01 4545
MY query:
SELECT a.itemid,a.inventdimid,max(a.datephysical),a.transrefid
FROM a where dataareaid = 'ermi'
group by a.itemid,a.inventdimid
it is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

Use the ANSI standard row_number() function:
select t.*
from (select t.*,
row_number() over (partition by itemid, inventdimid
order by datephysical desc) as seqnum
from table t
) t
where seqnum = 1;

Find max(a.datephysical) for each itemid, inventdimid combination, select all rows from that date.
SELECT itemid, inventdimid, datephysical, transrefid
FROM a a1
where dataareaid = 'ermi'
and datephysical = (select max(datephysical)
from a a2
where a1.itemid = a2.itemid
and a1.inventdimid = a2.inventdimid
and a2.dataareaid = 'ermi')

You have to create a temporary table with your GROUP BY and then join the original table with it.
Try this:
SELECT T1.*,T2.datephysical,T2.transrefid FROM
(SELECT itemid,inventdimid
FROM TableName
GROUP BY itemid,inventdimid) T1 JOIN
(SELECT itemid,inventdimid,datephysical,transrefid
FROM TableName) T2 ON T1.itemid=T2.itemid AND T1.inventdimid=T2.inventdimid

I'm assuming you want the transrefid corresponding with the a.datephysical shown? This would be done by turning the column into a subquery:
SELECT a.itemid,a.inventdimid,max(a.datephysical),
(SELECT b.transrefid FROM MY_TABLE b where
b.datareaid = 'ermi' and b.itemid = a.itemid and b.inventdimid = a.itemid
and b.datephysical = max(a.datephysical)) as transrefid
FROM MY_TABLE a where dataareaid = 'ermi'
group by a.itemid, a.inventdimid
Some databases may not support this syntax though and it will fail if there are more than one records with the same date.

Related

Concrete Rows of Id 2 with Id 1 IF Date is Same and All Row Names Should be different in SQL Server 2008R2 and

I have following Data in myRecords Table
Id Date Name Cash
1 11/25/2016 4:23.123 Ramesh 10000
2 11/25/2016 4:23.173 Suresh 15000
1 11/27/2016 5:23.320 Ramesh 30000
2 11/27/2016 5:23.670 Suresh 40000
and I want to create view So I can get data in following Format
Id1 Date1 Name1 Cash1 Id2 Date2 Name2 Cash2
1 11/25/2016 4:23.123 Ramesh 10000 2 11/25/2016 4:23.173 Suresh 15000
1 11/27/2016 5:23.320 Ramesh 30000 2 11/27/2016 5:23.670 Suresh 40000
How can I do it.
If you are doing date and there will always only be 2 records per day you could convert to drop off the time and do a self join:
DECLARE #myRecords AS TABLE (Id INT, DATE DATETIME, Name VARCHAR(20), CASH INT)
INSERT INTO #myRecords VALUES (1,'11/25/2016 4:23','Ramesh',10000),(2,'11/25/2016 4:23','Suresh',15000)
,(1,'11/27/2016 5:23','Ramesh',30000),(2,'11/27/2016 4:23','Suresh',40000)
SELECT
m1.Id as Id1
,m1.Date as Date1
,m1.Name as Name1
,m1.Cash as Cash1
,m2.Id as Id2
,m2.Date as Date2
,m2.Name as Name2
,m2.Cash as Cash2
FROM
#myRecords m1
LEFT JOIN #myRecords m2
ON CAST(m1.DATE AS DATE) = CAST(m2.DATE AS DATE)
AND m1.Id <> m2.Id
WHERE
m1.Id = 1
Then you can also introduce ROW_NUMBER() to figure out whatever order you want then take all of the ODD RowNumbers and SELF JOIN to the Even RowNumbers:
;WITH cte AS (
SELECT
*
,RowNum = ROW_NUMBER() OVER (ORDER BY Date)
FROM
#myRecords
)
SELECT *
FROM
cte c1
LEFT JOIN cte c2
ON c1.RowNum + 1 = c2.RowNum
WHERE
c1.RowNum % 2 <> 0
As long as your Id joining logic is unclear, this will help In this case but you will need to add Id Filter or additional Identity column and row_number() in future I guess.
SELECT
T.*, TT.*
FROM
[Table] AS T
INNER JOIN
[Table] AS TT
ON T.Date = TT.Date
You can use Cross Apply for the required result set.
SELECT [ID],
[DATE],
[NAME],
[CASH],
B.*
FROM #TABLE1 A
CROSS APPLY (SELECT ID AS ID2,
[DATE] AS DATE2,
[NAME] AS NAME2,
[CASH] AS CASH2
FROM #TABLE1 B
WHERE A.ID < B.ID
AND CONVERT(DATE, A.DATE) = CONVERT(DATE, B.DATE))B
This will also return the same result:
select a.id, a.date, a.name, a.cash, b.id as id2, b.date as date2,
b.name as name2, b.cash as cash2
from myTable a
inner join myTable b on a.id+1 = b.id
and cast(a.date as date) <> cast(b.date as date)

How to SUM Only One Time Per UniqueId in SQL?

I have two tables that look roughly like this:
Table A
DocumentId (*is unique) DocumentDate
1 2016-01-01
2 2016-01-01
3 2016-02-01
4 2016-03-01
and Table B
ContractId SnapshotTimeId NetFinanced
1 20160231 300
1 20160331 300
1 20160431 300
2 20160231 450
2 20160331 450
2 20160431 450
3 20160331 500
3 20160431 500
4 20160431 150
I would like the final table to look something like this:
DocumentDate NetFinanced
2016-01-01 750
2016-02-01 500
2016-03-01 150
I have tried the following and it doesn't work:
SELECT A.DocumentDate, SUM(B.NetFinanced)
FROM A
JOIN B on B.ContractId=A.DocumentId
GROUP BY A.DocumentDate
Any ideas? Thanks in advance
you can use distinct
SELECT A.DocumentDate,
SUM(B.NetFinanced)
FROM A
JOIN (SELECT DISTINCT
ContractId,
NetFinanced
FROM B
) B ON B.ContractId = A.DocumentId
GROUP BY A.DocumentDate
the result of this will be different if the NetFinanced amount changes per SnapshotTimeId
if you want the most recent NetFinanced amount, you can use Row_number() to order the values.
SELECT A.DocumentDate,
SUM(B.NetFinanced)
FROM A
JOIN (SELECT ROW_NUMBER() OVER (PARTITION BY ContractId ORDER BY SnapshotTimeId DESC) Rn,
ContractId,
NetFinanced
FROM B
) B ON B.ContractId = A.DocumentId AND B.Rn = 1
GROUP BY A.DocumentDate
You have duplicate values for NetFinanced in TableB, of course the results won't give you what you want. You need to join TableA with the unique values (I assume) of ContractId and NetFinanced columns from TableB:
SELECT A.DocumentDate,
SUM(B.NetFinanced) NetFinanced
FROM dbo.TableA A
INNER JOIN (SELECT DISTINCT ContractId, NetFinanced
FROM dbo.TableB) B
ON A.DocumentId = B.ContractId
GROUP BY A.DocumentDate;
Try Like this
SELECT A.DocumentDate, SUM(B.NetFinanced)
FROM A
JOIN (SELECT MAX(ContractId) ContractId, MAX(SnapshotTimeId)SnapshotTimeId,
MAX(NetFinanced)NetFinanced
FROM B GROUP BY ContractId) B ON B.ContractId = A.DocumentId
GROUP BY A.DocumentDate

How to Filter records with some column with similar value and some not

I have the following table A
Table A
ID Date Price
123 4/1/2015 300
123 4/1/2015 500
456 4/1/2015 200
456 5/1/2015 200
789 6/1/2015 300
368 NULL 700
Scenario: I want to pull all those records where date is same but price is not same:
for example:
ID Date Price
123 4/1/2015 300
123 4/1/2015 500
select t1.*
from your_table t1
join
(
select id
from your_table
group by id, date
having count(distinct price) > 1
) t2 on t1.id = t2.id
One method uses analytic functinos:
select t.*
from (select t.*, min(price) over (partition by id, date) as minprice,
max(price) over (partition by id, date) as maxprice
from t
) t
where minprice <> maxprice;
Another uses a simple exists:
select t.*
from t t
where exists (select 1 from t t2 where t2.id = t.id and t2.date = t.date);
Both of these methods assume that date has no time component. If it does, then use trunc(date) or similar logic.

SQL Nearest Past Date

Hi i have an issue on handling some data on SQL, and returning some values by the nearest date. I have two Tables:
Table 1
ID Content Date
--------------------------------------------
123 X 2013-11-18
123 ZE 2013-11-29
233 YX 2013-12-30
233 XX 2013-12-28
444 Z 2014-02-24
Table 2
ID Value Validation Date
--------------------------------------------
123 0.54 2013-11-11
123 0.42 2013-11-18
123 0.32 2013-11-27
233 1.2 2013-12-4
233 1.1 2013-12-28
233 1.0 2013-12-29
444 4 2014-02-11
444 3 2014-02-15
444 2 2014-02-23
The output that i pretend is something like:
ID Content Date Value Validation Date
------------------------------------------------------------------------
123 X 2013-11-18 0.42 2013-11-18
123 ZE 2013-11-29 0.32 2013-11-27
233 YX 2013-12-30 1.0 2013-12-29
233 XX 2013-12-28 1.1 2013-12-28
444 Z 2014-02-24 2 2014-02-23
So i would like to return back the value where the validation date is the nearest to the date (where the validation date has to be always smaller than the date). Can you please help me? The ID in table 1 and 2 is not unique.
You can use the following query:
SELECT ID, Content, [Date], Value, [Validation Date]
FROM (
SELECT t1.ID, Content, [Date], Value, [Validation Date],
ROW_NUMBER() OVER (PARTITION BY t1.ID, Content
ORDER BY DATEDIFF(d, [Validation Date], [Date])) AS rn
FROM Table1 AS t1
INNER JOIN Table2 AS t2 ON t1.ID = t2.ID AND [Validation Date] <= [Date]
) t
WHERE t.rn = 1
ROW_NUMBER() is used to track the record with the smallest [Date] -[Validation Date] difference per (ID, Content) pair of values.
try this :
SELECT a.id,
a.content,
a.date,
b.valu,
b.validationdate
FROM (select tt.id,
tt.content,
tt.date,
row_number() over(partition by tt.id order by tt.date desc) rn
from table1 tt) a
JOIN (select t.id,
t.content,
t.date,
t.valu,
t.validationdate,
row_number() over(partition by t.id order by t.validationdate desc) rn
from table2 t) b
on a.id=b.id and a.rn=b.rn
I think the only way to do this is correlation. Something like that.
SELECT a.id, a.content, a.date,
(SELECT TOP 1 b.value, b.validate
FROM table2 b
WHERE b.id=a.id
ORDER BY b.validate DESC) from table1 a
I think the best approach is to use outer apply:
select t1.id, t1.content, t1.date, t2.value, t2.validdate
from table1 t1 outer apply
(SELECT TOP 1 t2.value, t2.validdate
FROM table2 t2
WHERE t2.id = t1.id
ORDER BY t2.validdate DESC
) t2;

Find next date value in the column

I have a large table with the following columns and sample values:
ID Ser Reg Date
1 12345 001 1/3/2011
1 12345 001 2/2/2011
1 12345 002 1/3/2011
1 12345 002 2/2/2011
2 23456 001 1/3/2011
2 23456 001 2/7/2011
2 23456 001 3/5/2011
I tried this query from a previous post SQL - Select next date query - but did not get the desired results:
SELECT
mytable.id,
mytable.date,
(
SELECT
MIN(mytablemin.date)
FROM mytable AS mytablemin
WHERE mytablemin.date > mytable.date
) AS NextDate
FROM mytable
This is what I am trying to accomplish:
ID Ser Reg curr_Date prev_Date
1 12345 001 2/2/2011 1/3/2011
1 12345 002 2/2/2011 1/3/2011
2 23456 001 2/7/2011 1/5/2011
2 23456 001 3/5/2011 2/7/2011
I would appreciate any help with this task.
if you are using oracle database (as you have not mentioned then I can assume anything)
then you can use lead and lag function/command for this ..
select id,ser, reg, curr_date ,prev_date
from
(
select id,ser, reg, ser, date curr_date
LEAD(date, 1, 0) OVER (PARTITION BY id,ser, reg, curr_date ORDER BY date DESC NULLS LAST) prev_date,
)
where prev_date is not null;
There was a condition missing from correlated subquery joining mytablemin copy of mytable table with mytable. Also you would eliminate records which do not have NextDate - but this might give incorrect results in case when only one record in group (Id, Ser, Reg) exists by eliminating it from result set.
select * from
(
SELECT
mytable.id,
mytable.date,
(
SELECT
MIN(mytablemin.date)
FROM mytable AS mytablemin
WHERE mytablemin.date > mytable.date
and mytablemin.id = mytable.id
and mytablemin.Ser = mytable.Ser
and mytablemin.Reg = mytable.Reg
) AS NextDate
FROM mytable
) a
where a.NextDate is not null
And here is version using derived table with aggregation:
SELECT
mytable.id,
mytable.date,
mytablemin.minDate
FROM mytable
inner join
(
SELECT mytablemin.id,
mytablemin.Ser,
mytablemin.Reg,
MIN(mytablemin.date) minDate
FROM mytable AS mytablemin
group by mytablemin.id,
mytablemin.Ser,
mytablemin.Reg
having MIN(mytablemin.date) is not null
) AS mytablemin
on mytablemin.id = mytable.id
and mytablemin.Ser = mytable.Ser
and mytablemin.Reg = mytable.Reg