How to UNION parts of different sql - sql-server

I have 4 parts, each part is made out of 2 select statement. I need the 1st 2 part to be UNION'd with the 2nd part. Each part contains its own ORDER BY. I need the results to appear 1st part first and followed by the 2nd part. Only each part is sorted but not the overall result set.
(select col1,col2,col3,col4,col5 from tableA where col1 = 'x'
UNION ALL
select col1,col2,col3,col4,col5 from tableB where col1 = 'x'
ORDER BY Col3) --1st part ends here
--now I need to UNION the 2nd part
UNION ALL
(select col1,col2,col3,col4,col5 from tableA where col1 <> 'x'
UNION ALL
select col1,col2,col3,col4,col5 from tableB where col1 <> 'x'
ORDER BY Col3) --2nd part ends here
I tried wrapping each select in the SELECT * FROM (... but I'm having issues with ORDER BY. Just can't seem to get the syntax right.

Just add a column for this purpose:
select col1,col2,col3,col4,col5, ord = 1 from tableA where col1 = 'x'
UNION ALL
select col1,col2,col3,col4,col5, ord = 1 from tableB where col1 = 'x'
UNION ALL
select col1,col2,col3,col4,col5, ord = 2 from tableA where col1 <> 'x'
UNION ALL
select col1,col2,col3,col4,col5, ord = 2 from tableB where col1 <> 'x'
ORDER BY ord, Col3

The ORDER BY applies over the whole result set, after the UNION. See Example C: https://msdn.microsoft.com/en-us/library/ms180026%28v=sql.110%29.aspx
You can't have the ORDER BY in the queries within the UNION.

Related

Transforming and repeating multiple rows

I have a table that has two IDs within it named FamilyID and PersonID. I need to be able to repeat these rows with all combinations, as the below screenshot shows noting that each of the numbers get an extra row.
Here is some SQL to create the table with some sample data. There is no set number of occurrences that could occur.
Anyone aware of how we could be achieved?
CREATE TABLE #TempStackOverflow
(
FamilyID int,
PersonID int
)
insert into #TempStackOverflow
(
FamilyID,
PersonID
)
select
1012,
1
union
select
1013,
1
union
select
1014,
1
union
select
1015,
2
union
select
14774,
3
union
select
1019,
5
I understand that you need some sort of a complete list of matches within groups, but honestly, it would be much better if you would explain the business context, using plain English, in the first place.
The following query seems to produce your sample result:
with cte as (
select a.FamilyID, a.PersonID, a.PersonID as [GroupId] from #TempStackOverflow a
union all
select b.PersonID, b.FamilyID, b.PersonID from #TempStackOverflow b
)
select distinct c.FamilyID, s.PersonID
from cte c
inner join cte s on s.GroupId = c.GroupId
where c.FamilyID != s.PersonID;
Here is the simplest version I can come up with that groups the items by PersonId, as you do above. Obviously if you don't want that, then you can remove the outer query.
SELECT FamilyId,
PersonID
FROM (
SELECT FamilyId, PersonId, PersonID as SortBy
FROM #TempStackOverflow t1
UNION
SELECT PersonId, FamilyId, PersonId as SortBy
FROM #TempStackOverflow t1
UNION
SELECT t1.FamilyID, t2.FamilyID, t1.PersonID as SortBy
FROM #TempStackOverflow t1
FULL OUTER JOIN #TempStackOverflow t2
ON t1.PersonID = t2.PersonID
WHERE t1.FamilyID != t2.FamilyID
) as Src
ORDER BY SortBy

How can I find different elements between two columns (generated by two subqueries)?

My subqueries produce a result like this:
coulmn1 column2
a d
b z1000
c c
d
1
2
z1000 k
I want to know the different elements in both sets. column1 ={ a,b,c, 1,2,d, z1000,.....} column 2 ={ d,c,z1000,k......} The result I want is ={ a,k,1,2,....} hope I made it clear ..please let me know how could I do that..?
One method is full outer join:
select coalesce(t1.col1, t2.col2)
from t t1 full join
t t2
on t1.col1 = t2.col2
where t1.col1 is null or t2.col2 is null;
Another method doesn't require running the subquery twice;
select v.col
from t cross apply
(values (t.col1, 1), (t.col2, 2)) v(col, which)
group by v.col
having min(v.which) = max(v.which);
--Test Data
with temp_table as (
select 'a' coulmn1,'b' column2 union all
select 'b' coulmn1,'z1000' column2 union all
select 'c' coulmn1,'c' column2 union all
select 'd' coulmn1,'' column2 union all
select 'z1000' coulmn1,'k' column2
)
--use cross join and union to distinct data
--you have to change temp_table to your own table
select * into #temp_table from (
select T.coulmn1,T2.column2 as column2
from temp_table T,temp_table T2
where T.coulmn1 <> T2.column2
) T;
select coulmn1 from #temp_table
union
select column2 from #temp_table;
Test Link
Use EXCEPT for this.
SELECT column1
FROM your_subquery
EXCEPT
SELECT column2
FROM your_subquery
UNION
SELECT column2
FROM your_subquery
EXCEPT
SELECT column1
FROM your_subquery

Convert 2 rows to fields in SQL Server

In SQL server (2016), I want to convert 2 rows into 1 row with fields of both rows.
I have this example:
IF OBJECT_ID('tempdb.dbo.#MyTable') IS not NULL DROP TABLE #MyTable
CREATE TABLE #MyTable (
Direction varchar(1),
DateKey int,
ID varchar(8),
[Sessions] int
)
insert into #MyTable values('S', 20180301, 'ID123456', 46)
insert into #MyTable values('R', 20180301, 'ID123456', 99)
select * from #MyTable
Output:
Direction DateKey ID Sessions
S 20180301 ID123456 46
R 20180301 ID123456 99
The output I want is:
DateKey ID S_Sessions R_Sessions
20180301 ID123456 46 99
So I tried this query but it won't work:
select DateKey,ID,
case Direction
when 'S' then [Sessions] as S_Sessions -- Incorrect syntax near the keyword 'as'.
else [Sessions] as R_Sessions
end
from #MyTable
Maybe I have to create an extra table, insert rows where direction='S' and then update the records with data where direction='R' but I wonder if there is a better way to do this.
use PIVOT
select *
from #MyTable
pivot
(
max(Sessions)
for Direction in ([S], [R])
) p
assuming that your table contains the "pairs" S and R you can also use a self join
SELECT s.DateKey , s.ID , s.Sessions S_Sessions , r.Sessions R_Sessions
FROM #MyTable S
JOIN #MyTable R
ON s.ID = r.ID
AND s.DateKey = r.DateKey
WHERE S.Direction = 'S'
AND r.Direction = 'R'
CASE in SQL is an expression that returns a single value. It cannot be used to control execution flow like in procedural languages.
You can use conditional aggregation for this:
select DateKey, ID,
max(case Direction when 'S' then [Sessions] end) as S_Sessions,
max(case Direction when 'R' then [Sessions] end) as R_Sessions
from #MyTable
group by DateKey, ID
Demo here
Try It ... It works for me . more variable more case and more left join table.
select a.DateKey,a.ID,
(case a.Direction
when 'S' then a.Sessions
end) as S_Sessions,
(case b.Direction
when 'R' then b.Sessions
end) as R_Sessions
from mytable as a CROSS JOIN mytable as b ON a.ID=b.ID LIMIT 2,1

SQL while loop from select statement to insert values

New to high level SQL stuff.
Want to make it so that a select statement will fill in values 7 times then move onto the next row.
EXAMPLE:
X | Y
A 1
A 2
....
A 7
B 1
B 2
....
This is some code that I have.
WHILE (*select that queries letters of unique value*) IS NOT NULL
BEGIN
INSERT INTO table1 (X,Y) *select that queries letters of unique value*,1
INSERT INTO table1 (X,Y) *select that queries letters of unique value*,2
....
INSERT INTO table1 (X,Y) *select that queries letters of unique value*,7
END
Would love some help. Thanks!
Here is another way too:
SELECT *
FROM
(
SELECT 'A' AS VAL1
UNION
SELECT 'B'
) A
CROSS JOIN
(
SELECT 1 AS VAL2
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5
UNION
SELECT 6
UNION
SELECT 7
) B
ORDER BY A.VAL1
You can also do like:
CROSS JOIN
(
VALUES (1),(2),(3),(4),(5),(6),(7)
) B (VAL2)
ORDER BY A.VAL1
There is no need to use a loop, you can directly insert those values to your table like:
INSERT INTO YourTable (X, Y)
SELECT A.VAL1, B.VAL2
FROM...

How to change duplicate values to unique values in a column using by stored procedure in SQL Server

I have to change RowSpan value if OccupationalInjuryId's duplicate value exists. Here is the screenshot:
Should I use T-SQL or #temporary table structure. But I couldn't figure out how to fix. For example there are two values with OccupationalId = 1100 and both rowspan's are 2. It should be 1 for second value's RowSpan no.
My SQL query:
select *
from
(select
Row_Number() over (order by oi.Id) as RowNo,
oid.OccupationalInjuryId
from
OTH_OccupationalInjury oi
left join
OTH_OccupationalInjuryDetail oid on oi.Id = oid.OccupationalInjuryId
where
1 = 1) t1
left join
(select
count(OccupationalInjuryId) end as RowSpan,
oid.OccupationalInjuryId
from
OTH_OccupationalInjury oi
left join
OTH_OccupationalInjuryDetail oid on oi.Id = oid.OccupationalInjuryId
where
1=1
group by
OccupationalInjuryId
having
(Count(OccupationalInjuryId) > 1) ) t2 on t1.OccupationalInjuryId = t2.OccupationalInjuryId
END
If I got you correctly, you only care about first RowSpan value for each OccupationalInjuryId and for others you want 1. If I am wrong, correct me.
So, Can you try something like :
DECLARE #BaseTable TABLE(ID INT, OccupationalInjuryId INT, RowSpan INT)
INSERT INTO #BaseTable (ID, OccupationalInjuryId, RowSpan)
SELECT 1, 1100, 2 UNION ALL
SELECT 2, 1100, 2 UNION ALL
SELECT 3, 1099, 2 UNION ALL
SELECT 4, 1099, 3 UNION ALL
SELECT 5, 1106, NULL
SELECT
ID,
OccupationalInjuryId,
CASE WHEN rn = 1 THEN RowSpan ELSE 1 END AS RowSpan
FROM
(
SELECT ID, OccupationalInjuryId, RowSpan, ROW_NUMBER() OVER (PARTITION BY OccupationalInjuryId, RowSpan ORDER BY ID) AS rn FROM #BaseTable
) tmp

Resources