Sql Server 2008 table join - sql

I have written one query in SQL. I can't get correct output.
here I have attached screenshot.
This is query Output
but I want it like this

You don't need the union subquery (unless you need to remove duplicates). This should do what you want:
select max(case when status = 'O' then ref end) as O,
max(case when status = 'E' then ref end) as E,
max(case when status = 'A' then ref end) as A
from (select p.*, row_number() over (partition by status order by status) as seqnum
from nl_pmnt
where status in ('O', 'E', 'A')
) p
group by seqnum

Try this:
select [O],[E],[A] from (
select row_number() over (order by (select null)) [RN], ref [O] from nl_pmnt where [status] = 'O' and ref <> ''
) [O] left join (
select row_number() over (order by (select null)) [RN], ref [E] from nl_pmnt where [status] = 'O' and ref <> ''
) [E] on [O].[RN] = [E].[RN] left join (
select row_number() over (order by (select null)) [RN], ref [A] from nl_pmnt where [status] = 'O' and ref <> ''
) [A] on [O].[RN] = [A].[RN]

You can use PIVOT
SELECT [O],[E],[A] FROM (
select ROW_NUMBER() OVER( PARTITION BY status ORDER BY (SELECT NULL)) RN, ref, status from nl_pmnt
where ref <> '') SRC
PIVOT(MAX(ref) FOR status IN ([O],[E],[A])) PVT

Related

Concatenated string split

I have a table Customer in SQL Server 2016 that has a text column with values
I=3;A=500;D=20210422
I would like to split the I=3,A=500 & D=20210422 into 3 columns in a new table or view.
One method is:
select t.*, s.*
from t cross apply
(select max(case when s.value like 'I=%' then stuff(s.value, 1, 2, '') end) as i,
max(case when s.value like 'A=%' then stuff(s.value, 1, 2, '') end) as a,
max(case when s.value like 'D=%' then stuff(s.value, 1, 2, '') end) as d
from string_split(t.col, ';') s
) s;
Here is a db<>fiddle.
Presumably these are just sample values and will vary? If you don't need to guarantee any particular ordering of the columns a simple solution is to use string_split and a conditional case expression to aggregate into new columns:
with v as (
select value, Row_Number() over (order by (select null)) rn
from String_Split('I=3;A=500;D=20210422',';')
)
select
Max(case when rn=1 then value end) Col1,
Max(case when rn=2 then value end) Col2,
Max(case when rn=3 then value end) Col3
from v
This works:
DECLARE #userData TABLE(
var1 varchar(30) NOT NULL,
var2 varchar(30) NOT NULL,
var3 varchar(30) NOT NULL
);
WITH CTE_Data
AS(
SELECT 'I=3,A=500,D=20210422' AS [MyData]
)
,CTE_Detaildata
AS(
SELECT
P.*
FROM(
SELECT
LEFT(v.[Value], 1) [ID],
v.[Value] AS [Data]
FROM CTE_Data AS d
CROSS APPLY STRING_SPLIT(d.[MyData], ',') AS v
)AS D
PIVOT(MIN(D.[Data]) FOR D.[ID] IN ([I],[A],[D])) AS P
)
INSERT INTO #userData(var1, var2, var3)
SELECT
d.[A],
d.[D],
d.[I]
FROM CTE_Detaildata AS d
SELECT * FROM #userData;

How to combine multiple rows data until next row value is not null in SQL Server

I have data like this and there is no id column to group, for example:
A
B
C
NULL
F
D
R
NULL
R
T
G
Expected output:
ABC
FDR
RTG
This is a gaps-and-island problem. One option uses a cumulative sum to define the groups, then aggregation - but you need a column that defines the ordering of the rows, I assumed id.
select string_agg(val, '') within group (order by id) vals
from (
select
val,
sum(case when val is null then 1 else 0 end) over(order by id) grp
from mytable
) t
group by grp
order by grp
If there may be consecutive nulls, then you need a where clause in the outer query:
select string_agg(val, '') within group (order by id) vals
from (
select
val,
sum(case when val is null then 1 else 0 end) over(order by id) grp
from mytable
) t
where val is not null
group by grp
order by grp
You could also use window counts to build the groups:
select string_agg(val, '') within group (order by id) vals
from (
select
val,
count(*) over(order by id) cnt1,
count(val) over(order by id) cnt2
from mytable
) t
group by cnt1 - cnt2
order by cnt1 - cnt2

Inline Views with JOIN ON syntax possible?

I have two inline views that I can join via the classic join method. Results are as expected.
However, trying to adapt to JOIN ON syntax, I cannot see how. Restriction? WITH required? Or need to create two separate views and then apply - I presume will work. Cannot find anything in this regard.
The view is as follows, trying to get a match between BUY and SELL.
select BUY.*, SELL.* from (
select Z.*, 'LONG' from (
select X.commodity, X.market_place, X.max_qty, Y.maturity_dt, rank() over
(partition by X.commodity, X.market_place order by y.maturity_dt ASC) as
rank_val
from
(select commodity, market_place, max(qty) as max_qty
from OPEN_POSITIONS
where prod_type = 'future'
and qty > 0
group by commodity, market_place
) X,
open_positions Y
where Y.qty = X.max_qty
and Y.commodity = X.commodity
and Y.prod_type = 'future'
and Y.market_place = X.market_place ) Z
where Z.rank_val = 1 ) BUY,
(
select Z.*, 'SHORT' from (
select X.commodity, X.market_place, X.min_qty, Y.maturity_dt, rank() over
(partition by X.commodity, X.market_place order by y.maturity_dt ASC) as
rank_val
from
(select commodity, market_place, min(qty) as min_qty
from OPEN_POSITIONS
where prod_type = 'future'
and qty < 0
group by commodity, market_place
) X,
open_positions Y
where Y.qty = X.min_qty
and Y.commodity = X.commodity
and Y.prod_type = 'future'
and Y.market_place = X.market_place ) Z
where Z.rank_val = 1) SELL
where BUY.commodity = SELL.commodity
and BUY.market_place = SELL.market_place
You can try something like below based on the database.
;With AllData AS
(
select commodity, market_place, qty
from OPEN_POSITIONS
where prod_type = 'future'
),
X AS
(
SELECT
commodity, market_place, max(qty) as max_qty
FROM AllData
WHERE qty > 0
group by commodity, market_place
),
Z AS
(
SELECT
X.commodity, X.market_place, X.max_qty, Y.maturity_dt, rank() over
(partition by X.commodity, X.market_place order by y.maturity_dt ASC) as rank_val
FROM AllData Y INNER JOIN X ON Y.qty = X.max_qty AND Y.commodity = X.commodity AND Y.market_place = X.market_place
),
BUY AS
(
SELECT
commodity, market_place, max_qty, maturity_dt,rank_val
FROM Z
WHERE rank_val = 1
),
A AS
(
SELECT
commodity, market_place, max(qty) as max_qty
FROM AllData
WHERE qty < 0
group by commodity, market_place
),
B AS
(
SELECT
A.commodity, A.market_place, A.max_qty, Y.maturity_dt, rank() over
(partition by A.commodity, A.market_place order by y.maturity_dt ASC) as rank_val
FROM AllData Y INNER JOIN A ON Y.qty = A.max_qty AND Y.commodity = A.commodity AND Y.market_place = A.market_place
),
SELL AS
(
SELECT
commodity, market_place, max_qty, maturity_dt,rank_val
FROM B
WHERE rank_val = 1
)
SELECT
bu.*;sl.*
FROM BUY bu INNER JOIN SELL AS sl ON bu.commodity = sl.commodity
and bu.market_place = sl.market_place
Not possible, need to make a view first

Show data from same table in different column but in same row in MSSQL

Let I have tables as
What I want to do is to select data like
OUTPUT{ID,FirstName,LastName,SkillONE,SkillOneExp,SkillTwo,SkillTwoExp,SkillThree,SkillThreeExp}
here SkillOne will show most experienced skill (like java, C++), SkillOneExp is the year of exp of that skill and so on. Will show only 3 like this. For each employee there will be only one row.
I tried as
select
e.ID
,e.FirstName
,e.LastName
,es.experience
,CAST
(
CASE
WHEN tf.rownumber = 1
THEN tf.skill_description
END
AS varchar(50)
)as SKILLONE
,CAST
(
CASE
WHEN tf.rownumber = 1
THEN tf.experience
END
AS varchar(50)
)as SKILLONE_EXP
,CAST
(
CASE
WHEN tf.rownumber = 2
THEN tf.skill_description
END
AS varchar(50)
)as SKILTWO
,CAST
(
CASE
WHEN tf.rownumber = 2
THEN tf.experience
END
AS varchar(50)
)as SKILLTWO_EXP
from
Employee e
JOIN
EmployeeSkill es
on es.ID=e.ID
JOIN
skills s
on s.skill_ID=es.skill_ID
JOIN
(
select * from
(
(select
ROW_NUMBER() OVER (ORDER BY es2.experience ASC) AS rownumber,
es2.ID
,es2.skill_ID
,es2.experience
,s2.skill_description
from
EmployeeSkill es2
JOIN
skills s2
on
s2.skill_ID=es2.skill_ID
)
) as tf2
)as tf
on tf.id= e.id
By using this I am not getting proper result. I am using MS SQL 2012.
SELECT
emp.ID,
emp.FirstName,
emp.LastName,
MIN(CASE i WHEN 1 THEN ski.skill_description END) AS SkillOne ,
MIN(CASE i WHEN 1 THEN ski.experience END) AS SkillOneExp ,
MIN(CASE i WHEN 2 THEN ski.skill_description END) AS SkillTwo ,
MIN(CASE i WHEN 2 THEN ski.experience END) AS SkillTwoExp ,
MIN(CASE i WHEN 3 THEN ski.skill_description END) AS SkillThree ,
MIN(CASE i WHEN 3 THEN ski.experience END) AS SkillThreeExp
FROM
Employee AS emp
CROSS APPLY (
SELECT TOP 3
ROW_NUMBER() OVER(ORDER BY experience DESC) i,
CAST(skill_description AS varchar(50),
CAST(experience AS varchar(50)
FROM EmployeeSkill t1
INNER JOIN skills t2
ON (t1.skill_ID = t2.skill_ID)
ORDER BY experience DESC
) AS ski
GROUP BY
emp.ID,
emp.FirstName,
emp.LastName
by editing the query by #anon I solved my problem. thanks a lot to him.
SELECT
emp.ID,
emp.FirstName,
emp.LastName,
MIN(CASE i WHEN 1 THEN ski.skill_description END) AS SkillOne ,
MIN(CASE i WHEN 1 THEN ski.experience END) AS SkillOneExp ,
MIN(CASE i WHEN 2 THEN ski.skill_description END) AS SkillTwo ,
MIN(CASE i WHEN 2 THEN ski.experience END) AS SkillTwoExp ,
MIN(CASE i WHEN 3 THEN ski.skill_description END) AS SkillThree ,
MIN(CASE i WHEN 3 THEN ski.experience END) AS SkillThreeExp
FROM
Employee AS emp
CROSS APPLY (
SELECT TOP 3
ROW_NUMBER() OVER(ORDER BY experience DESC) i,
CAST(skill_description AS varchar(50) ) AS skill_description,
CAST(experience AS varchar(50) ) AS experience
FROM EmployeeSkill t1
INNER JOIN skills t2
ON (t1.skill_ID = t2.skill_ID) AND t1.ID=emp.ID
ORDER BY experience DESC
) AS ski
GROUP BY
emp.ID,
emp.FirstName,
emp.LastName

How to store result of sql query in variable?

I have the following query:
with cte as
(SELECT top 10 [1],[2]
FROM [tbl_B] where [2] > '2000-01-01' and Status_7 = 0 and Status_8 = 1
ORDER BY [2])
,
CTE1 AS
( select [1], row_number() over (order by [2]) as rn
from CTE
)
select [1] from CTE1 where rn = '10'
how can I put this into a variable to compare it to another query result?
If i use set #123 = (above query) it gives errors.
with cte as
(
SELECT top 10 [1],[2]
FROM [tbl_B]
where [2] > '2000-01-01' and Status_7 = 0 and Status_8 = 1
ORDER BY [2]
)
,CTE1 AS
(
select [1], row_number() over (order by [2]) as rn
from CTE
)
select #123 = [1] from CTE1 where rn = '10'
with cte as
(SELECT top 10 [1],[2]
FROM [tbl_B] where [2] > '2000-01-01' and Status_7 = 0 and Status_8 = 1
ORDER BY [2])
,
CTE1 AS
( select [1], row_number() over (order by [2]) as rn
from CTE
)
select #123 = [1] from CTE1 where rn = '10'
You can use a table variable to store the CTE's result set. For example:
declare #table_var table (id int, col1 varchar(50));
; with CTE as
(
... your definition here ...
)
insert #table_var
(id, col1)
select id
, col1
from CTE
Comparing this with another set can be done with a full outer join:
select coalesce(t1.id, t2.id) as id
, coalesce(t1.col1, t2.col1) as col1
, case
when t1.id is null then 'Missing in t1'
when t2.id is null then 'Missing in t2'
when isnull(t1.col1,'') <> isnull(t2.col1,'') then 'Col1 is different'
else 'Identical'
end as Difference
from #table_var1 t1
full outer join
#table_var2 t2
on t1.id = t2.id