Sql server union but keep order - sql-server

Is there a way to union two tables, but keep the rows from the first table appearing first in the result set?
For example:
Table1
name surname
-------------------
John Doe
Bob Marley
Ras Tafari
Table2
name surname
------------------
Lucky Dube
Abby Arnold
I want the result set to look like:
name surname
-------------------
John Doe
Bob Marley
Ras Tafari
Lucky Dube
Abby Arnold
Unfortunately, union somehow reorders the table. Is there a way around this?

Try this :-
Select *
from
(
Select name,surname, 1 as filter
from Table1
Union all
Select name,surname , 2 as filter
from Table2
)
order by filter

The only way to guarantee output order is to use ORDER BY:
SELECT name,surname,1 as rs
FROM table1
UNION ALL
SELECT name,surname,2
FROM table2
ORDER BY rs
If you don't want rs to appear in the final result set, do the UNION as a subquery:
SELECT name,surname
FROM (
SELECT name,surname,1 as rs
FROM table1
UNION ALL
SELECT name,surname,2
FROM table2
) t
ORDER BY rs

;WITH cte as (
SELECT name, surname, 1 as n FROM table1
UNION ALL
SELECT name, surname, 2 as n FROM table2
UNION ALL
SELECT name, surname, 3 as n FROM table3
)
SELECT name, surname
FROM cte
ORDER BY n;

.Like this?
CREATE TABLE #Table1 (Names VARCHAR(50))
CREATE TABLE #Table2 (Names VARCHAR(50))
INSERT INTO #Table1
(
Names
)
VALUES
('John Doe'), ('Bob Marley'), ('Ras Tafari')
INSERT INTO #Table2
(
Names
)
VALUES
('Lucky Dube'), ('Abby Arnold')
SELECT ArbSeq = 1, *
FROM #Table1
UNION ALL
SELECT ArbSeq = 2, *
FROM #Table2
ORDER BY ArbSeq
It should be noted that ordering is not guaranteed when not explicitly defined.
If the table features a clustered index, the rows will typically be returned in the index's order - but this is not guaranteed.

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

Insert by ignoring Row Number ()

I have two tables A and B
Both the table have Row Number field
Table A
RowNumber Id Name Address
1 1 ABC India
2 2 XYZ Australia
Table B
RowNumber Id Name Address
1 3 ABC India
I need to insert the Table B's value at the end of Table A. As the Table A is holding RowNumber field so the Table B's value is not coming at the end of Table A's value, it is displaying after the First row of Table A. But I need the Value at the End of Table A. Please help
Give an extra column value to just for the sake of sorting.
Query
select t.[RowNUmber], t.[Id], [Name], [Address] from(
select [RowNumber], [Id], [Name], [Address], 0 as [sortby]
from [TableA]
union all
select [RowNumber], [Id], [Name], [Address], 1 as [sortby]
from [TableB]
)t
order by t.[sortby], t.[RowNumber];
If you order by ID then you will get the expected result in the selection but for the insertion you have to make RowNumber column as IDENTITY then it will insert next record with `RowNumber 3,4,5....so on
SELECT RowNumber, Id, Name, Address from TableA
UNION ALL
SELECT RowNumber, Id, Name, Address from TableB
ORDER BY ID
TRY to insert in the following way and give the max value of TableA so that it will generate number after that:
INSERT INTO TableA
SELECT (row_number() OVER (ORDER BY rownumber)+2) AS n,
id,
name,
address
FROM TableB

SQL joined table pivot without aggregate

I have two tables:
Table1
ID TYPE
1 ABC1
2 ABC2
3 ABC3
Table2
ID Data
1 100
1 101
2 10
2 90
And I want the results to look like this:
ID Data1 Data2
1 100 101
2 10 90
But I'm having a total mare with my attempts at creating the pivot. So far I have:
With Inital_Data As (
Select
A.ID,
B.Data As Data1,
B.Data As Data2
From
Table1 A join
Table2 B on
A.ID = B.ID
)
Select *
From
Initial_Data
PIVOT
(Max(ID) FOR Data IN (Data1,Data2)) p
I know this is rubbish but so far even the logic of what I'm trying to achieve is escaping me, let alone the syntax! Can anyone give me a guiding hand?
Pivot with more than one column needs some tricks, I prefer the XML concatenation. First I take all values for each ID in only one XML, then you can take these values one by one:
Just paste this into an empty query window and execute. Adapt for your needs
EDIT: Includes column Type from TABLE1 as Caption for ID...
DECLARE #Table1 TABLE(ID INT,[TYPE] VARCHAR(10));
INSERT INTO #Table1 VALUES
(1,'ABC1')
,(2,'ABC2')
,(3,'ABC3');
DECLARE #Table2 TABLE(ID INT,DATA INT);
INSERT INTO #Table2 VALUES
(1,100)
,(1,101)
,(2,10)
,(2,90);
WITH DistinctIDs AS
(
SELECT DISTINCT tbl2.ID,tbl1.[TYPE]
FROM #Table2 AS tbl2
INNER JOIN #Table1 AS tbl1 ON tbl1.ID=tbl2.ID
)
SELECT ID,[TYPE]
,concatXML.x.value('/root[1]/item[1]/#data','int') AS Data1
,concatXML.x.value('/root[1]/item[2]/#data','int') AS Data2
FROM DistinctIDs AS dIDs
CROSS APPLY
(
SELECT ID AS [#id],DATA AS [#data]
FROM #Table2 AS tbl WHERE tbl.ID=dIDs.ID
FOR XML PATH('item'), ROOT('root'),TYPE
) AS concatXML(x)

Is it possible to improve sort perfomance of ID-based list of rows?

Consider following example:
SET NOCOUNT ON;
CREATE TABLE #Users
(
ID INT IDENTITY(1,1),
Name VARCHAR(50)
);
CREATE CLUSTERED INDEX IDX_C_Users_UserID ON #Users(ID);
-- CREATE INDEX IDX_Users_Name ON #Users(Name); -- It doesn't work.
CREATE TABLE #Towns
(
ID INT IDENTITY(1,1),
Name VARCHAR(50)
);
CREATE CLUSTERED INDEX IDX_C_Towns_UserID ON #Towns(ID)
CREATE TABLE #BeenHere
(
ID INT IDENTITY(1,1), -- for some business reason we can't use clustered index on them
UserID INT,
TownID INT
);
CREATE UNIQUE INDEX IDX_BEEN_THERE ON #BeenHere(TownID, UserID);
INSERT INTO #Towns
SELECT Prefix+Suffix FROM (
SELECT Prefix, Suffix FROM
(SELECT 'China' UNION ALL
SELECT 'Ham' UNION ALL
SELECT 'Chicken' UNION ALL
SELECT 'Great' UNION ALL
SELECT 'Loud'
) as A(Prefix)
CROSS JOIN
(SELECT 'town' UNION ALL
SELECT 'water' UNION ALL
SELECT ' City' UNION ALL
SELECT 'burg' UNION ALL
SELECT 'berg') AS B(Suffix)
) Q
ORDER BY NEWID()
;
INSERT INTO #Users(Name)
SELECT Name + ' ' + Surname FROM (
SELECT Name, Surname FROM
(SELECT 'John' UNION ALL
SELECT 'Mary' UNION ALL
SELECT 'Ann' UNION ALL
SELECT 'Salomon' UNION ALL
SELECT 'Lisa' UNION ALL
SELECT 'Patricia' UNION ALL
SELECT 'David' UNION ALL
SELECT 'Patrick' UNION ALL
SELECT 'John' UNION ALL
SELECT 'Harry' UNION ALL
SELECT 'Richard' UNION ALL
SELECT 'George'
) as A(Name)
CROSS JOIN
(SELECT 'Smith' UNION ALL
SELECT 'Kowalski' UNION ALL
SELECT 'Bush' UNION ALL
SELECT 'Truman' UNION ALL
SELECT 'Clinton' UNION ALL
SELECT 'Reagan' UNION ALL
SELECT 'Lincoln' UNION ALL
SELECT 'Goldberg' UNION ALL
SELECT 'Adams' UNION ALL
SELECT 'Wilson' UNION ALL
SELECT 'Carter') as B(Surname)
) P
ORDER BY NEWID();
INSERT INTO #BeenHere(UserID, TownID)
SELECT
TOP 10 PERCENT
#Users.ID,
#Towns.ID
FROM
#Users
CROSS JOIN
#Towns
ORDER BY NEWID();
SET NOCOUNT OFF;
SELECT
Towns.Name,
(SELECT Users.ID, Users.Name FROM #Users Users INNER JOIN #BeenHere BH ON Users.ID = BH.UserID WHERE BH.TownID = Towns.ID ORDER BY Users.Name FOR XML PATH('User'), ROOT('Users'), TYPE) as BeenThere
FROM #Towns Towns
ORDER BY Towns.Name;
DROP TABLE #BeenHere;
DROP TABLE #Users;
DROP TABLE #Towns;
As we can see in execution plan, sorting users cost 78% of resources consumed by last query.
Is it possible to place some index on these tables to improve sorting perfomance? I can't introduce backward incompatible changes to database, like providing clustered index on #BeenHere(UserID, TownID).
I simply replaced your clustered index into this one:
CREATE CLUSTERED INDEX IDX_C_Users_Name_UserID ON #Users(Name, ID);
So now your table is sorted by Name, not by ID.
SORT operator is gone from execution plan.
UPDATE
As you said, you cannot change clustered index. There's one way to do that if you want. Your NONCLUSTERED INDEX on Name only column is fine, but SQL Server decides not to use it. What you can do is to add a HINT to your table to use this index:
SELECT Towns.Name
, (
SELECT Users.ID, Users.Name
FROM #Users Users WITH (INDEX (IDX_Users_Name))
INNER JOIN #BeenHere BH
ON Users.ID = BH.UserID
WHERE BH.TownID = Towns.ID
ORDER BY Users.Name
FOR XML PATH('User'), ROOT('Users'), TYPE
) AS BeenThere
FROM #Towns Towns
ORDER BY Towns.Name;
Then your query will use this index and sort operator will no longer be there. However, I'm not sure if it's the most efficient way. SQL Server has to Scan index then, instead of seeking it.
Your problem is the use of a correlated subquery. Stop using those and use joins (including derived tables if you must) instead. Correlated subqueries run row-by-row and not against the whole set and thus are preformance hogs. one.

How to find the maximum value in join without using if in sql stored procedure

I have a two tables like below
A
Id Name
1 a
2 b
B
Id Name
1 t
6 s
My requirement is to find the maximum id from table and display the name and id for that maximum without using case and if.
i findout the maximum by using below query
SELECT MAX(id)
FROM (SELECT id,name FROM A
UNION
SELECT id,name FROM B) as c
I findout the maximum 6 using the above query.but i can't able to find the name.I tried the below query but it's not working
SELECT MAX(id)
FROM (SELECT id,name FROM A
UNION
SELECT id,name FROM B) as c
How to find the name?
Any help will be greatly appreciated!!!
First combine the tables, since you need to search both. Next, determine the id you need. JOIN the id back with the temporarily created table to retreive the name that belongs to that id:
WITH tmpTable AS (
SELECT id,name FROM A
UNION
SELECT id,name FROM B
)
, max AS (
SELECT MAX(id) id
FROM tmpTable
)
SELECT t.id, t.name
FROM max m
JOIN tmpTable t ON m.id = t.id
You could use ROW_NUMBER(). You have to UNION ALL TableA and TableB first.
WITH TableA(Id, Name) AS(
SELECT 1, 'a' UNION ALL
SELECT 2, 'b'
)
,TableB(Id, Name) AS(
SELECT 1, 't' UNION ALL
SELECT 6, 's'
)
,Combined(Id, Name) AS(
SELECT * FROM TableA UNION ALL
SELECT * FROM TableB
)
,CTE AS(
SELECT *, RN = ROW_NUMBER() OVER(ORDER BY ID DESC) FROM Combined
)
SELECT Id, Name
FROM CTE
WHERE RN = 1
Just order by over the union and take first row:
SELECT TOP 1 * FROM (SELECT * FROM A UNION SELECT * FROM B) x
ORDER BY ID DESC
This won't show ties though.
For you stated that you used SQL Server 2008. Therefore,I used FULL JOIN and NESTED SELECT to get what your looking for. See below:
SELECT
(SELECT
1,
ISNULL(A.Id,B.Id)Id
FROM A FULL JOIN B ON A.Id=B.Id) AS Id,
(SELECT
1,
ISNULL(A.Name,B.Name)Name
FROM A FULL JOIN B ON A.Id=B.Id) AS Name
It's possible to use ROW_NUMBER() or DENSE_RANK() functions to get new numiration by Id, and then select value with newly created orderId equal to 1
Use:
ROW_NUMBER() to get only one value (even if there are some repetitions of max id)
DENSE_RANK() to get all equal max id values
Here is an example:
DECLARE #tb1 AS TABLE
(
Id INT
,[Name] NVARCHAR(255)
)
DECLARE #tb2 AS TABLE
(
Id INT
,[Name] NVARCHAR(255)
)
INSERT INTO #tb1 VALUES (1, 'A');
INSERT INTO #tb1 VALUES (7, 'B');
INSERT INTO #tb2 VALUES (4, 'C');
INSERT INTO #tb1 VALUES (7, 'D');
SELECT * FROM
(SELECT Id, Name, ROW_NUMBER() OVER (ORDER BY Id DESC) AS [orderId]
FROM
(SELECT Id, Name FROM #tb1
UNION
SELECT Id, Name FROM #tb2) as tb3) AS TB
WHERE [orderId] = 1
SELECT * FROM
(SELECT Id, Name, DENSE_RANK() OVER (ORDER BY Id DESC) AS [orderId]
FROM
(SELECT Id, Name FROM #tb1
UNION
SELECT Id, Name FROM #tb2) as tb3) AS TB
WHERE [orderId] = 1
Results are:

Resources