I am struggling with a problem that i'm trying to solve on a ORACLE DB 19.0.0.0.0
I have a TABLE like this:
ID | CODE | AMOUNT | VAR1 | VAR2
+-------------------------------
10 | 255 |192.50 |CLOSED | 1
10 | 342 |192.50 |OPEN | 7
10 | 921 |255.00 |RUNNING| 2
10 | 222 |255.00 |CLOSED | 10
13 | 101 |10.00 |RUNNING| 3
13 | 122 |19.25 |RUNNING| 7
71 | 804 |21.25 |OPEN | 9
71 | 744 |21.25 |RUNNING| 2
13 | 100 |950.00 |OPEN | 10
90 | 126 |17.80 |RUNNING| 0
90 | 137 |9.00 |RUNNING| 0
And i need to select rows that have the same ID and same AMOUNT.
they can form pairs, trios or more,
In other words, i need to discard IDs and AMOUNTs that are unique.
The others columns can have any value
I expect to return:
ID | CODE | AMOUNT | VAR1 | VAR2
+-------------------------------
10 | 255 |192.50 |CLOSED | 1
10 | 342 |192.50 |OPEN | 7
10 | 921 |255.00 |RUNNING| 2
10 | 222 |255.00 |CLOSED | 10
71 | 804 |21.25 |OPEN | 9
71 | 744 |21.25 |RUNNING| 2
I already tried doing a query that return only the unique
ID + AMOUNT rows, creating an "UNIQUE KEYS TABLE", and then a JOIN or a WHERE in the TABLE, but in my
case it is not efficient enough
What is the best and efficient way to solve this ?
You should add an INDEX on all three columns, whichmake the query much faster.
On bigger databases INNER JOIN is faster than an IN clause
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE Table1
("ID" int, "CODE" int, "AMOUNT" int, "VAR1" varchar2(7), "VAR2" int)
;
CREATE INDEX tab1_index_address
ON Table1("ID","CODE","AMOUNT");
INSERT ALL
INTO Table1 ("ID", "CODE", "AMOUNT", "VAR1", "VAR2")
VALUES (10, 255, 192.50, 'CLOSED', 1)
INTO Table1 ("ID", "CODE", "AMOUNT", "VAR1", "VAR2")
VALUES (10, 342, 192.50, 'OPEN', 7)
INTO Table1 ("ID", "CODE", "AMOUNT", "VAR1", "VAR2")
VALUES (10, 921, 255.00, 'RUNNING', 2)
INTO Table1 ("ID", "CODE", "AMOUNT", "VAR1", "VAR2")
VALUES (10, 222, 255.00, 'CLOSED', 10)
INTO Table1 ("ID", "CODE", "AMOUNT", "VAR1", "VAR2")
VALUES (13, 101, 10.00, 'RUNNING', 3)
INTO Table1 ("ID", "CODE", "AMOUNT", "VAR1", "VAR2")
VALUES (13, 122, 19.25, 'RUNNING', 7)
INTO Table1 ("ID", "CODE", "AMOUNT", "VAR1", "VAR2")
VALUES (71, 804, 21.25, 'OPEN', 9)
INTO Table1 ("ID", "CODE", "AMOUNT", "VAR1", "VAR2")
VALUES (71, 744, 21.25, 'RUNNING', 2)
INTO Table1 ("ID", "CODE", "AMOUNT", "VAR1", "VAR2")
VALUES (13, 100, 950.00, 'OPEN', 10)
INTO Table1 ("ID", "CODE", "AMOUNT", "VAR1", "VAR2")
VALUES (90, 126, 17.80, 'RUNNING', 0)
INTO Table1 ("ID", "CODE", "AMOUNT", "VAR1", "VAR2")
VALUES (90, 137, 9.00, 'RUNNING', 0)
SELECT * FROM dual;
Query 1:
SELECT tab1.*
FROM Table1 tab1 INNER JOIN
Table1 tab2 ON tab1.ID = tab2.ID AND tab1."AMOUNT" = tab2."AMOUNT"
AND tab1.CODE <> tab2.CODE
Results:
| ID | CODE | AMOUNT | VAR1 | VAR2 |
|----|------|--------|---------|------|
| 10 | 921 | 255 | RUNNING | 2 |
| 10 | 342 | 193 | OPEN | 7 |
| 10 | 255 | 193 | CLOSED | 1 |
| 10 | 222 | 255 | CLOSED | 10 |
| 71 | 804 | 21 | OPEN | 9 |
| 71 | 744 | 21 | RUNNING | 2 |
WITH CTE(ID ,CODE , AMOUNT , VAR1 , VAR2)AS
(
SELECT 10 , 255 ,192.50 ,'CLOSED' , 1 UNION ALL
SELECT 10 , 342 ,192.50 ,'OPEN' , 7 UNION ALL
SELECT 10 , 921 ,255.00 ,'RUNNING', 2 UNION ALL
SELECT 10 , 222 ,255.00 ,'CLOSED' , 10 UNION ALL
SELECT 13 , 101 ,10.00 ,'RUNNING', 3 UNION ALL
SELECT 13 , 122 ,19.25 ,'RUNNING', 7 UNION ALL
SELECT 71 , 804 ,21.25 ,'OPEN' , 9 UNION ALL
SELECT 71 , 744 ,21.25 ,'RUNNING', 2 UNION ALL
SELECT 13 , 100 ,950.00 ,'OPEN' , 10 UNION ALL
SELECT 90 , 126 ,17.80 ,'RUNNING', 0 UNION ALL
SELECT 90 , 137 ,9.00 ,'RUNNING', 0
)
SELECT C.ID,C.CODE,C.AMOUNT,C.VAR1,C.VAR2
FROM CTE C
JOIN
(
SELECT X.ID,X.AMOUNT
FROM CTE X
GROUP BY X.ID,X.AMOUNT
HAVING COUNT(*)>1
)ZZ ON C.ID=ZZ.ID AND C.AMOUNT=ZZ.AMOUNT
Sorry, today dbfiddle for Oracle does not work for me, so solution tested on MS SQL Server
We can use a subquery to fetch the rows having same id and amount and then use IN in an outer query to add the remaining columns:
SELECT id, code, amount, var1, var2
FROM yourtable
WHERE (id, amount)
IN
(SELECT id, amount
FROM yourtable
GROUP BY id, amount
HAVING COUNT(*)>1)
ORDER BY id;
Tested with your sample data here: db<>fiddle
Related
When I run a query, these are the results presented to me:
id account_id score active item_id
5 78 9 true 4
6 78 1 true 4
7 78 9 true 6
8 78 5 true 7
9 78 5 true 8
10 78 5 true 8
I'd like the output to look like this by combining item_id's based on score:
id account_id score active item_id
* 78 10 true 4
7 78 9 true 6
8 78 5 true 7
* 78 10 true 8
My query that returns that info looks like this:
SELECT item.id, item.account_id, itemaudit.score, itemrevision.active, itemaudit.item_id
from item
left join itemrevision on item.id = itemrevision.id
join itemaudit on item.id = itemaudit.id
where itemrevision.active = true
;
The bit I'm missing is when 'item_id' is not distinct, combine/sum the value of 'score'. I'm not sure how to do this step.
The schema looks like this:
CREATE TABLE item
(id integer, account_id integer);
CREATE TABLE itemaudit
(id integer, item_id integer, score integer);
CREATE TABLE itemrevision
(id int, active boolean, item_id int);
INSERT INTO item
(id, account_id)
VALUES
(5, 78),
(6, 78),
(7, 78),
(8, 78),
(9, 78),
(10, 78)
;
INSERT INTO itemaudit
(id, item_id, score)
VALUES
(5, 4, 5),
(6, 4, 1),
(7, 6, 9),
(8, 7, 10),
(9, 8, 1),
(10, 8, 9)
;
INSERT INTO itemrevision
(id, active, item_id)
VALUES
(5, true, 4),
(6, true, 4),
(7, true, 6),
(8, true, 7),
(9, true, 7),
(10, true, 8)
;
If I understand correctly, you just want an aggregation query:
select ia.item_id, sum(ia.score) as score
from item i join -- the `where` clause turns this into an inner join
itemrevision ir
on i.id = ir.id join
itemaudit ia
on i.id = ia.id
where ir.active = true
group by ia.item_id;
Notes:
I changed the left join to an inner join, because the where clause has this effect anyway.
Table aliases make the query easier to write and to read.
In an aggregation query, the other columns are not appropriate.
I think you want something like this..
SELECT
CASE
WHEN array_length(array_agg(id),1) = 1
THEN (array_agg(id))[1]::text
ELSE '*'
END AS id,
account_id,
sum(score) AS score,
item_id
FROM item
GROUP BY account_id, item_id
ORDER BY account_id, item_id;
id | account_id | score | item_id
----+------------+-------+---------
* | 78 | 10 | 4
7 | 78 | 9 | 6
8 | 78 | 5 | 7
* | 78 | 10 | 8
(4 rows)
While this is what you want the simpler versions is more detailed and better.
SELECT
array_agg(id) AS id,
account_id,
sum(score) AS score,
item_id
FROM item
GROUP BY account_id, item_id
ORDER BY account_id, item_id;
id | account_id | score | item_id
--------+------------+-------+---------
{5,6} | 78 | 10 | 4
{7} | 78 | 9 | 6
{8} | 78 | 5 | 7
{9,10} | 78 | 10 | 8
(4 rows)
I have generated an extensive view which simulates certain occurrences based on different statistic models. These models are defined in each column header by a number and the maximum value of a row is the best model.
The table generated looks (partially) as follows;
+--------+----+------+------+------+------+------+------+
| Number | LI | PHSE | 0505 | 0506 | 0507 | 0508 | 0509 | [...] etc.
+--------+----+------+------+------+------+------+------+
| 100254 | 2 | M1 | 44 | 46 | 45 | 44 | 44 |
| 100254 | 2 | M2 | 36 | 36 | 35 | 37 | 37 |
| 100254 | 2 | M3 | 5 | 5 | 5 | 5 | 5 |
| 100254 | 2 | R1 | 34 | 36 | 37 | 37 | 37 |
| 100254 | 2 | R2 | 41 | 41 | 40 | 41 | 41 |
| 100329 | 1 | M1 | 37 | 38 | 38 | 38 | 39 |
| 100329 | 1 | M2 | 31 | 29 | 28 | 29 | 29 |
| 100329 | 1 | M3 | 6 | 6 | 6 | 6 | 6 |
| 100329 | 1 | R1 | 29 | 29 | 29 | 30 | 30 |
| 100329 | 1 | R2 | 25 | 26 | 26 | 27 | 26 |
+--------+----+------+------+------+------+------+------+
[...] etc.
Now I want to find the highest value in each row and display the corresponding column name as such;
| Number | LI | PHSE | MAXCOL |
+--------+----+------+--------+
| 100254 | 2 | M1 | 0506 |
| 100254 | 2 | M2 | 0508 |
| 100254 | 2 | M3 | 0505 |
| 100254 | 2 | R1 | 0507 |
| 100254 | 2 | R2 | 0505 |
+--------+----+------+--------+
[...] etc.
This is derived from 100254 - 2 - M1 largest value 46 occurring in column 0506, etc.
I've been toying around with PIVOT functions but no success there. I've also looked for an Index/Match equivalent like in Excel but since I can't refer to column headers as values this obviously won't work (and haven't found such function either).
Any help would be hugely appreciated.
UPDATE per Damien's comment:
An excerpt from the code that led to this:
SELECT DISTINCT sub2.Number, sub2.LI, sub2.PHSE
, sum(sub2.[0505]) over (partition by sub2.Number, sub2.LI, sub2.PHSE) as '0505'
, sum(sub2.[0506]) over (partition by sub2.Number, sub2.LI, sub2.PHSE) as '0506'
[...] etc. /*64 rows*/
FROM
(SELECT DISTINCT sub.*
, CASE WHEN sub.MF > sub.[5PAV] - sub.[5PSTDEV] THEN 1 ELSE 0 END AS '0505'
, CASE WHEN sub.MF > sub.[5PAV] - sub.[6PSTDEV] THEN 1 ELSE 0 END AS '0506'
[...] etc. /*64 rows*/
FROM
(SELECT DISTINCT ra.*
, sum(ra.qtyr) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 5 preceding AND 1 preceding) /
sum(ra.qtyu) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 5 preceding AND 1 preceding) AS '5PAV'
, sum(ra.qtyr) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 6 preceding AND 1 preceding) /
sum(ra.qtyu) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 6 preceding AND 1 preceding) AS '6PAV'
[...] etc. /*8 rows*/
, stdev(ra.MF) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 4 preceding AND CURRENT row) AS '5PSTDEV'
, stdev(ra.MF) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 5 preceding AND CURRENT row) AS '6PSTDEV'
[...] etc. /*8 rows*/
FROM ra
) AS sub
) AS sub2
No doubt that this may be one of the most ineffective uses of SQL, but time-pressure and inexperience made me write it this way.
Any suggestions to change this code and achieve the desired table result more efficiently would be much appreciated too.
EDIT per Anton's answer;
The above code summarized as pvt continues as follows;
SELECT Number, LI, PHSE, combo, hitrate
FROM (...) AS pvt
UNPIVOT
(Hitrate FOR Combo IN (
[0505],
[0506],
[...] etc.)) AS upvt
Great solution to an inelegant problem.
You need to use UNPIVOT, not PIVOT
https://msdn.microsoft.com/en-us/library/ms177410.aspx
If the number of columns is variable, you have to use dynamic sql to construct the list of columns
If you want to see all MAXCOL (equal columns) try this:
CREATE TABLE table1 (
Number NUMERIC(10),
LI numeric(10),
PHSE NVARCHAR(10),
[0505] numeric(10),
[0506] numeric(10),
[0507] numeric(10),
[0508] numeric(10),
[0509] numeric(10))
INSERT INTO table1 VALUES(100254,2,'M1',44 ,46 ,45 ,44,44)
INSERT INTO table1 VALUES(100254,2,'M2',36,36,35,37,37)
INSERT INTO table1 VALUES(100254,2,'M3',5,5,5,5,5)
INSERT INTO table1 VALUES(100254,2,'R1',34,36,37,37,37)
INSERT INTO table1 VALUES(100254,2, 'R2',41,41,40,41,41)
INSERT INTO table1 VALUES(100329,1, 'M1',37,38,38,38,39)
INSERT INTO table1 VALUES(100329,1, 'M2',31,29,28,29,29)
INSERT INTO table1 VALUES(100329,1, 'M3',6,6,6,6,6)
INSERT INTO table1 VALUES(100329,1, 'R1',29,29,29,30,30)
INSERT INTO table1 VALUES(100329,1, 'R2',25,26,26,27,26)
SELECT *
INTO #UNPIVOT
FROM table1
UNPIVOT ( num
FOR MAXCOL IN ([0505],[0506],[0507],[0508],[0509])) AS k
SELECT A.Number,A.LI,A.PHSE,A.num,B.MAXCOL FROM
(SELECT number,LI,PHSE,MAX(num) AS num FROM #UNPIVOT GROUP BY number,LI,PHSE) A
LEFT JOIN
(SELECT * FROM #UNPIVOT) B ON A.num=B.num AND A.Number=B.Number AND A.LI=B.LI AND A.PHSE=B.PHSE
I would use CROSS APPLY as follows:
WITH Src AS
(
SELECT * FROM (VALUES
(100254, 2, 'M1', 44, 46, 45, 44, 44),
(100254, 2, 'M2', 36, 36, 35, 37, 37),
(100254, 2, 'M3', 5, 5, 5, 5, 5),
(100254, 2, 'R1', 34, 36, 37, 37, 37),
(100254, 2, 'R2', 41, 41, 40, 41, 41),
(100329, 1, 'M1', 37, 38, 38, 38, 39),
(100329, 1, 'M2', 31, 29, 28, 29, 29),
(100329, 1, 'M3', 6, 6, 6, 6, 6),
(100329, 1, 'R1', 29, 29, 29, 30, 30),
(100329, 1, 'R2', 25, 26, 26, 27, 26)) T(Number, LI, PHSE, [0505], [0506], [0507], [0508], [0509])
)
SELECT Number, LI, PHSE, MaxCol
FROM Src
CROSS APPLY (SELECT TOP 1 * FROM (VALUES
('0505', [0505]),
('0506', [0506]),
('0507', [0507]),
('0508', [0508]),
('0509', [0509])
) T(MaxCol, Val) ORDER BY Val DESC) Q
Note that equal columns may be chosen randomly unless some additional value is specified, i.e. MaxCol.
Update
You need dynamic query, like following one:
DECLARE #sql nvarchar(MAX) =
'SELECT Number, LI, PHSE, MaxCol
FROM Src
CROSS APPLY (SELECT TOP 1 * FROM (VALUES' +STUFF(
(SELECT ',(', QUOTENAME(name, '''')+','+QUOTENAME(name)+')'
FROM sys.columns
WHERE object_id=OBJECT_ID('Src') AND name NOT IN ('Number', 'LI', 'PHSE')
FOR XML PATH('')), 1, 1, '')+') T(MaxCol, Val) ORDER BY Val DESC) Q';
EXEC(#sql);
Src is your table name, replace it accordingly.
You can use UNPIVOT and CROSS APPLY.
With this solution you don't have to specify all the columns multiple times.
Source data:
CREATE TABLE Student
([Name] varchar(5), [Maths] int, [Science] int, [English] int)
;
INSERT INTO Student
([Name], [Maths], [Science], [English])
VALUES
('Tilak', 90, 40, 60),
('Raj', 30, 50, 70)
;
Solution:
with foo as (
select name, subject, marks
from student
unpivot
(
marks
for subject in (Science, Maths, English)
) u
)
select distinct f1.name, f2.subject
from foo f1
cross apply (
select top 1 name, subject
from foo
where f1.Name = Name
order by Marks desc) f2
Result:
--------------------------------------------------
| Name | Subject
--------------------------------------------------
| Tilak | Maths
--------------------------------------------------
| Raj | Science
--------------------------------------------------
http://sqlfiddle.com/#!18/780cd8/5
Source:
Seq Amount
1 50
2 48
3 46
4 40
5 45
6 43
7 39
Here is what I want,
when the amount in currernt row is larger than the last one, It changes to the previous one.
For example in row 5, the amount 45>40 in row 4, then change it to 40
in row 6, the amount 43>40 in updated row5, then change it to 40
This is the expected result:
Seq Amount
1 50
2 48
3 46
4 40
5 40
6 40
7 39
I am currently using lag (amount) over (order by seq)
however, the result is not correct. I think I need a loop script but I am not sure how to do that, please help.
Thanks!
Here is a more generic version not requiring LAG:
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE Table1
([Seq] int, [Amount] int)
;
INSERT INTO Table1
([Seq], [Amount])
VALUES
(1, 50),
(2, 48),
(3, 46),
(4, 40),
(5, 45),
(6, 43),
(7, 39)
;
Query 1:
select t1.Seq, case when t1.Amount < t2.Amount or t2.Amount is null then t1.Amount else t2.Amount end as Value
from Table1 t1
left join Table1 t2 on t2.Seq = t1.Seq - 1
order by t1.Seq
Results:
| Seq | Value |
|-----|-------|
| 1 | 50 |
| 2 | 48 |
| 3 | 46 |
| 4 | 40 |
| 5 | 40 |
| 6 | 43 |
| 7 | 39 |
Update the column using the logic provided by RedFilter in a while loop until the value of ##rowcount = 0
I have a table like this:
Id Num Some text
--------------------
1 1 ""
2 1 ""
3 2 ""
4 2 ""
5 2 ""
6 2 ""
7 3 ""
What I want is a query to select the first ten distinct nums, so if I want to get the two first nums I'll get the first six rows. I'm using MariaDB.
Try this approach:
select *
from Table1 as T1
join (
select distinct num
from Table1
order by num
limit 2 ) as T2
on T1.num = T2.num
;
In a fiddle here: http://sqlfiddle.com/#!9/1468ad/5
In MySQL you can use LIMIT. The caveat is that LIMIT is not directly supported in the IN sub-queries and therefore you must use a sub-query inside a IN sub-query:
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Table1
(`Id` int, `Num` int, `Some text` varchar(2))
;
INSERT INTO Table1
(`Id`, `Num`, `Some text`)
VALUES
(1, 1, '""'),
(2, 1, '""'),
(3, 2, '""'),
(4, 2, '""'),
(5, 2, '""'),
(6, 2, '""'),
(7, 3, '""')
;
Query 1:
select * from Table1
where Num in (select Num FROM(select distinct Num from Table1 order by Num limit 2)a)
Results:
| Id | Num | Some text |
|----|-----|-----------|
| 1 | 1 | "" |
| 2 | 1 | "" |
| 3 | 2 | "" |
| 4 | 2 | "" |
| 5 | 2 | "" |
| 6 | 2 | "" |
I am using SQL server 2008 and I am trying to unpivot the data. Here is the SQL code that I am using,
CREATE TABLE #pvt1 (VendorID int, Sa int, Emp1 int,Sa1 int,Emp2 int)
GO
INSERT INTO #pvt1 VALUES (1,2,4,3,9);
GO
--Unpivot the table.
SELECT distinct VendorID,Orders,Orders1
FROM
(SELECT VendorID, Emp1, Sa,Emp2,Sa1
FROM #pvt1 ) p
UNPIVOT
(Orders FOR Emp IN
(Emp1,Emp2)
)AS unpvt
UNPIVOT
(Orders1 FOR Emp1 IN
(Sa,Sa1)
)AS unpvt1;
GO
And Here is the result of the above code.
VendorID Orders Orders1
1 4 2
1 4 3
1 9 2
1 9 3
But I want my Output to be the way indicated below
VendorID Orders Orders1
1 4 2
1 9 3
The relationship from the above code is 2 is related to 4, and 3 is related to 9.
How can I achieve this?
An easier way to unpivot the data would be to use a CROSS APPLY to unpivot the columns in pairs:
select vendorid, orders, orders1
from pvt1
cross apply
(
select emp1, sa union all
select emp2, sa1
) c (orders, orders1);
See SQL Fiddle with Demo. Or you can use CROSS APPLY with the VALUES clause if you don't want to use the UNION ALL:
select vendorid, orders, orders1
from pvt1
cross apply
(
values
(emp1, sa),
(emp2, sa1)
) c (orders, orders1);
See SQL Fiddle with Demo
The answer by Taryn is indeed super useful, and I'd like to expand one aspect of it.
If you have a very un-normalized table like this, with multiple sets of columns for e.g. 4 quarters or 12 months:
+-------+------+------+------+------+------+------+-------+------+
| cYear | foo1 | foo2 | foo3 | foo4 | bar1 | bar2 | bar3 | bar4 |
+-------+------+------+------+------+------+------+-------+------+
| 2020 | 42 | 888 | 0 | 33 | one | two | three | four |
+-------+------+------+------+------+------+------+-------+------+
Then the CROSS APPLY method is easy to write and understand, when you got the hang of it. For the numbered column, use constant values.
SELECT
cYear,
cQuarter,
foo,
bar
FROM temp
CROSS APPLY
(
VALUES
(1, foo1, bar1),
(2, foo2, bar2),
(3, foo3, bar3),
(4, foo4, bar4)
) c (cQuarter, foo, bar)
Result:
+-------+----------+-----+-------+
| cYear | cQuarter | foo | bar |
+-------+----------+-----+-------+
| 2020 | 1 | 42 | one |
| 2020 | 2 | 888 | two |
| 2020 | 3 | 0 | three |
| 2020 | 4 | 33 | four |
+-------+----------+-----+-------+
SQL Fiddle
I needed composit key AND skip extras row in case when data is missing (NULLs). For ex. when x2 and y2 are possible replacement vendor and price
WITH pvt AS (SELECT * FROM (VALUES
( 1, 6, 11, 111, 12, 13, 122, 133),
( 2, 6, 21, 211, 22, 23, 222, 233),
( 3, 6, 31, 311, 32, 33, 322, 333),
( 5, 4, 41, 411, 42, NULL, 422, NULL),
( 6, 4, 51, 511, 52, NULL, 522, NULL))
s( id, s, a, b, x1, x2, y1, y2)
)
-- SELECT * FROM pvt
SELECT CONCAT('xy_',s,'_', id, postfix) as comp_id, a, b, x, y
FROM pvt
CROSS APPLY
(
VALUES
(NULL, x1, y1),
('_ext', x2, y2)
) c (postfix, x, y)
WHERE x IS NOT NULL
produces
comp_id a b x y
-------------------------------- ----------- ----------- ----------- -----------
xy_6_1 11 111 12 122
xy_6_1_ext 11 111 13 133
xy_6_2 21 211 22 222
xy_6_2_ext 21 211 23 233
xy_6_3 31 311 32 322
xy_6_3_ext 31 311 33 333
xy_4_5 41 411 42 422
xy_4_6 51 511 52 522
(8 rows affected)
from:
id s a b x1 x2 y1 y2
----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
1 6 11 111 12 13 122 133
2 6 21 211 22 23 222 233
3 6 31 311 32 33 322 333
5 4 41 411 42 NULL 422 NULL
6 4 51 511 52 NULL 522 NULL
(5 rows affected)