How to get previous row data in sql server - sql

I would like to get the data from previous row. I have used LAG function but did not get the expected result.
Table:-
col1 col2 col3
ABCD 1 Y
ABCD 2 N
ABCD 3 N
EFGH 4 N
EFGH 5 Y
EFGH 6 N
XXXX 7 Y
Expected result
col1 col2 col3 col4
ABCD 1 A NULL
ABCD 2 B A
ABCD 3 C B
EFGH 4 A NULL
EFGH 5 B A
EFGH 6 E B
XXXX 7 F NULL
Col4 should hold the data from previous row grouping by the value in Col1.
Please let me know how can this be achieved.

Use lag() function
select *, lag(col3) over (partition by col1 order by col2) as col4
from table t;
However You can also use subquery if your SQL doesn't have LAG()
select *,
(select top 1 col3
from table
where col1 = t.col1 and col2 < t.col2
order by col2 desc
) as col4
from table t;

Assuming SQL Server 2012 or newer...
SELECT
*,
LAG(col3) OVER (PARTITION BY col1 ORDER BY col2) AS col4
FROM
yourTable
If you're on SQL Server 2008 or older...
SELECT
*,
(
SELECT TOP(1) previous.col3
FROM yourTable AS previous
WHERE previous.col1 = yourTable.col1
AND previous.col2 < yourTable.col2
ORDER BY previous.col2 DESC
)
AS col4
FROM
yourTable

If you are on 2008 or earlier, try this:
select t1.col1, t1.col2, t1.col3, t2.col3 as col4
from table1 t1
left join table1 t2 on t1.col1 = t2.col1 and t1.col2 - 1 = t2.col2
the lag() function is the bee's knees, though. Use that, if you can.

Thank you all for the replies. By using the lag function with partition I got the expected result. I missed to used partition previously and due to that I was getting wrong results.

Related

Group by clause in Sql and filtering on an option,

I am working on a code, and the columns will something be like
Col1 Col2 Col3
10 1 A
10 2 B
11 3 C
11 4 c
So i am grouping by Col1 and whereever Col3 = A i need the whole information for that number of Col1. so in above example,i want the output as
Col1 col2 col3
10 1 A
10 2 B
Can someone please help.
Thanks in advance
You can use EXISTS and a correlating subquery to check if a row with the same col1 and a col3 of 'A' exists.
SELECT *
FROM elbat t1
WHERE EXISTS (SELECT *
FROM elbat t2
WHERE t2.col1 = t1.col1
AND t2.col3 = 'A');

SQL Server : get max of the column2 and column3 value must be 1

I have an output of some part of my stored proedure like this:
col1 col2 col3 col4
--------------------------
2016-05-05 1 2 2
2016-05-05 1 3 32
2016-05-12 2 1 11
2016-05-12 3 1 31
Now I need to get result based on this condition
col2 = 1 and col3 = max or col3 = 1
and col2 = max
The final result should be
col1 col2 col3 col4
-------------------------
2016-05-05 1 3 32
2016-05-12 3 1 31
Not sure if thats the most efficient way , but you can use ROW_NUMBER() :
SELECT * FROM (
SELECT t.*,
ROW_NUMBER() OVER(PARTITION BY t.col1 ORDER BY t.col3 DESC) as rnk,
WHERE t.col2 = 1
UNION ALL
SELECT t.*,
ROW_NUMBER() OVER(PARTITION BY t.col1 ORDER BY t.col2 DESC) as rnk,
WHERE t.col3 = 1) tt
WHERE rnk = 1
This will give you all the records with
(col2=1 and col3=max) or (col3=1 and col2=max)
This is a bit tricky. Your data has no ambiguities, such as duplicate maximuma in col4 or "1" values in both col2 and col3.
The following is a direct translation of the logic in your question:
select t.*
from t
where t.col4 = (select max(t2.col4)
from t t2
where t2.col1 = t.col1 and (t2.col2 = 1 or t2.col3 = 1)
);
Try this. Note if there are more than 1 same max value, then you need all of those in output. And it will work for all scenarios, even when col1 is not in sync with col2 and col3.
I am first finding highest values of col2 and col3 and assigning them value as 1. Then in outer query, I am using your join condition. Demo created for Postgres DB as SQLServer wasn't available.
SQLFiddle Demo
select col1,col2,col3,col4
from
(
select t.*,
RANK() OVER(ORDER BY col3 DESC) as col3_max,
RANK() OVER(ORDER BY col2 DESC) as col2_max
from your_table t
) t1
where
(col2=1 and col3_max=1)
OR
(col3=1 and col2_max=1)
Alternative way:
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY col1 ORDER BY iif(col2 = 1, col3, col2) DESC) as r
FROM tbl) t
WHERE r = 1

Query to get the rows in a table where value in column 1 is mapped to exactly one value in column 2

I have a table T1 like below:
COL1 COL2
---------------
aaa 10
bbb 20
bbb 20
bbb 10
ccc 30
ccc 30
aaa 30
ddd 30
I want col1 and col2 values where col1 is mapped to only one col2.
COL1 COL2
-----------
ccc 30
ddd 30
Please let me know how to achieve my goal.
I tried with the following to get required result set:
select distinct col1, col2
from t1
where col1 in (select col1
from (select distinct col1, col2 from t1)
group by col1
having count(col2) = 1);
What are the other options without having those many inner queries.
Thanks In Advance.
select Col1
, max(Col2) as Col2
from YourTable
group by
Col1
having count(distinct Col2) = 1
The having clause makes sure there's only one Col2 in a single group. You can display it using max, min or even avg.
See it working at SQL Fiddle (thanks to Amit Singh.)
Select Distinct A.Col1,A.Col2 from Table1 A
inner join
(Select Col1,Count(Distinct Col2) as col3 from Table1 group by Col1) B on
A.Col1=B.Col1 and B.Col3=1
Sql Fiddle

pivot data using SQL

I'm new to SQL and I'm wondering how to pivot a table like:
Col1 Col2 Col3
1 a w
2 a x
1 b y
2 b z
Into
Col1 a b
1 w y
2 x z
I was playing with GROUP BY but I can't seem to be able to turn unique rows into columns
This can be done using an aggregate function with a CASE expression:
select col1,
max(case when col2 = 'a' then col3 end) a,
max(case when col2 = 'b' then col3 end) b
from yourtable
group by col1
See SQL Fiddle with Demo
If you are using an RDBMS with a PIVOT function (SQL Server 2005+ / Oracle 11g+), then your query would be similar to this (Note: Oracle syntax below):
select *
from
(
select col1, col2, col3
from yourtable
)
pivot
(
max(col3)
for col2 in ('a', 'b')
)
See SQL Fiddle with Demo
The last way that you can do this is by using multiple joins on the same table:
select t1.col1,
t1.col3 a,
t2.col3 b
from yourtable t1
left join yourtable t2
on t1.col1 = t2.col1
and t2.col2 = 'b'
where t1.col2 = 'a'
See SQL Fiddle with Demo
All give the result:
| COL1 | 'A' | 'B' |
--------------------
| 1 | w | y |
| 2 | x | z |
If you require that the distinct values in Col2 can change without forcing changes on your query definition, you may be looking for an OLAP structure like SQL Analysis Services.
You should try something like
select * from
(select Col1, Col2, Col3 from TableName)
pivot xml (max(Col3)
for Col2 in (any) )
I'm on a mobile so I can't test if it's working right now.

SQL Server - Query to return groups with multiple distinct records

My table:
Col1 Col2
1 xyz
1 abc
2 abc
3 yyy
4 zzz
4 zzz
I have a table with two columns. I want to query for records where col1 has more than one DISTINCT col2 values. In the example table given above, the query should return records for col1 with value "1".
Expected query result:
Col1 Col2
1 xyz
1 abc
SELECT *
FROM tableName
WHERE Col1 IN
(
SELECT Col1
FROM tableName
GROUP BY Col1
HAVING COUNT(DISTINCT col2) > 1
)
SQLFiddle Demo
select t.col1, t.col2
from (
select col1
from tbl
group by col1
having MIN(col2) <> MAX(col2)
) x
join tbl t on t.col1 = c.col1