How to specify the order results with a SQL UNION? - sql

I'm trying to run the following query:
select * from (select * from customquestionbank where questionid=6 or secondquestionid=6
union select * from customquestionbank where questionid=5 or secondquestionid=5
union select * from customquestionbank where questionid=10 or secondquestionid=10
union select * from customquestionbank where questionid=11 or secondquestionid=11) Tabled
Being new to this site I cannot post images yet, but here is what the result look like:
questionid -> 5,6 ,10,11
However, I want the result to be displayed in the same order as my select statements above. In other words, questionid=6 returned first, then 5, and so on.

You don't need all the unions, just make it like this:
SELECT DISTINCT *
FROM customquestionbank
WHERE questionid IN ( 6, 5, 10, 11 )
OR secondquestionid IN ( 6, 5, 10, 11 )
ORDER BY CASE
WHEN 6 IN ( questionid, secondquestionid ) THEN 0
WHEN 5 IN ( questionid, secondquestionid ) THEN 1
WHEN 10 IN ( questionid, secondquestionid ) THEN 2
WHEN 11 IN ( questionid, secondquestionid ) THEN 3
END

If your RDBMS supports the VALUES constructor
SELECT questionid, secondquestionid
FROM (VALUES(6,1),
(5, 2),
(10, 3),
(11, 4)) V(q, ord)
JOIN customquestionbank
ON q IN ( questionid, secondquestionid )
GROUP BY questionid, secondquestionid
ORDER BY MIN(ord)

if your RDBMS is mysql, I think you can try ORDER BY FIELD like this:
SELECT *
FROM customquestionbank
WHERE
questionid IN(6, 5, 10, 11)
OR secondquestionid IN(6, 5, 10, 11)
ORDER BY FIELD(questionid, 6) ASC

Remove the super select that you are using
Write the query as
Select * from query1 union
Select * from query2 union
Select * from query3;
This will bring your result as needed
Else try this
Select col1,col2 from( Select 1,q1.* from query1 q1 union
Select 2,q2.* from query2 q2 union
Select 3,q1.* from query3 q3)
select only the required columns in the super query

Replace Union with Union ALL
create table #t
(
id int
)
insert into #t(id)values(5)
insert into #t(id)values(2)
insert into #t(id)values(4)
insert into #t(id)values(3)
Select * from
(
Select * from #t where id = 5
uNION All
Select * from #t where id = 2
uNION All
Select * from #t where id = 4
uNION All
Select * from #t where id = 3
)K
DROP TABLE #t

Related

How to select a record which have all id's in SQL?

I want select record which have all id's.
Example:
Name
ID
Ram
3
Ajay
1
Mogan
3
Ram
1
Ram
2
Here Ram have all id's (1,2,3). So, I want result as Ram.
WITH CTE(NAME,CODE)AS
(
SELECT 'RAM',1 UNION ALL
SELECT'AJAY',3 UNION ALL
SELECT 'MOGAN',2 UNION ALL
SELECT 'KUMAR',3 UNION ALL
SELECT 'RAM',2 UNION ALL
SELECT 'JAYA',1 UNION ALL
SELECT 'KABIL',3 UNION ALL
SELECT 'RAM',3
)
SELECT C.NAME
FROM CTE AS C
GROUP BY C.NAME
HAVING COUNT(DISTINCT C.CODE)=(SELECT COUNT(DISTINCT CODE) FROM CTE )
As far as I know, this is called "relational division". You can try my query or look for another possible solution
Select * from table where upper(name) = 'RAM'
This query would bring back all the IDs for RAM alone
how about string agg.
CREATE TABLE MyTable (
ID int,
Name varchar(255),
);
Insert into MyTable(ID, Name) values (1, 'Ram');
Insert into MyTable(ID, Name) values (2, 'Ram');
Insert into MyTable(ID, Name) values (3, 'Ram');
Insert into MyTable(ID, Name) values (1, 'Ajay');
Insert into MyTable(ID, Name) values (1, 'Mogan');
select Name, string_agg(ID, ',') as Ids
from MyTable
group by Name;
result
Ajay 1
Mogan 1
Ram 1,2,3
see result here
http://sqlfiddle.com/#!18/923bf/4
With reference to the with clause used by #surgey above,
WITH CTE(NAME,CODE)AS
(
SELECT 'RAM',1 from dual UNION ALL
SELECT'AJAY',3 from dual UNION ALL
SELECT 'MOGAN',2 from dual UNION ALL
SELECT 'KUMAR',3 from dual UNION ALL
SELECT 'RAM',2 from dual UNION ALL
SELECT 'JAYA',1 from dual UNION ALL
SELECT 'KABIL',3 from dual UNION ALL
SELECT 'RAM',3 from dual
)
select name, code, rank() over(partition by name order by code) rank
from cte
this query, it will bring back everybody in the and group them by name. THis could be one possible solution other use tou can use an "IN" clause in your where as shown below
Select * from table where upper(name) in ('RAM','AJAY')
If are you using MySql this will solve your issue:
SELECT r1.name
FROM raws r1
LEFT JOIN raws r2 ON r1.id = r2.id AND r1.name = r2.name
WHERE r2.id IN (1, 2, 3)
GROUP by r1.name
HAVING count(r2.id) = 3; # count of numbers in IN (1, 2, 3)
And if you have identifier in your table use it for join instead
of r1.id = r2.id AND r1.name = r2.name

Merge three tables in Select query by rule 3, 2, 1 records from each table

Merge three tables in a Select query by rule 3, 2, 1 records from each table as follows:
TableA: ID, FieldA, FieldB, FieldC,....
TableB: ID, FieldA, FieldB, FieldC,....
TableC: ID, FieldA, FieldB, FieldC,....
ID : auto number in each table
FieldA will be unique in all three tables.
I am looking for a Select query to merge three tables as follows:
TOP three records from TableA sorted by ID
TOP two records from TableB sorted by ID
TOP 1 record from TableC sorted by ID
Repeat this until select all records from all three tables.
If some table has fewer records or does not meet the criteria, ignore that and continue with others.
My attempt:
I did it totally through programming way, like cursors and If conditions inside a SQL Server stored procedure.
It makes delay.
This requires a formula that takes row numbers from each table and transforms it into a series of integers that skips the desired values.
In the query below, I am adding some CTE for the sake of shortening the formula. The real magic is in the UNION. Also, I am adding an additional field for your control. Feel free to get rid of it.
WITH A_Aux as (
SELECT 'A' As FromTable, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum, TableA.*
FROM TableA
), B_Aux AS (
SELECT 'B' As FromTable, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum, TableB.*
FROM TableB
), C_Aux AS (
SELECT 'C' As FromTable, ROW_NUMBER() OVER (Order BY ID) AS RowNum, TableC.*
FROM TableC
)
SELECT *
FROM (
SELECT RowNum+3*FLOOR((RowNum-1)/3) As ColumnForOrder, A_Aux.* FROM A_Aux
UNION ALL
SELECT 3+RowNum+4*FLOOR((RowNum-1)/2), B_Aux.* FROM B_Aux
UNION ALL
SELECT 6*RowNum, C_Aux.* FROM C_Aux
) T
ORDER BY ColumnForOrder
PS: note the pattern Offset + RowNum + (6-N) * Floor((RowNum-1)/N) to group N records together (it of course simplifies a lot for TableC).
PPS: I don't have a SQL server at hand to test it. Let me know if there is a syntax error.
You may try this..
GO
select * into #temp1 from (select * from table1) as t1
select * into #temp2 from (select * from table2) as t2
select * into #temp3 from (select * from table3) as t3
select * into #final from (select col1, col2, col3 from #temp1 where 1=0) as tb
declare #i int
set #i=1
while( (select COUNT(*) from #temp1)>#i)
Begin
;with ct1 as (
select ROW_NUMBER() over (order by id) as Slno, * from #temp1
),ct2 as (
select ROW_NUMBER() over (order by id) as Slno, * from #temp2
),ct3 as (
select ROW_NUMBER() over (order by id) as Slno, * from #temp3
),cfinal as (
select top 3 * from #temp1
union all
select top 2 * from #temp2
union all
select top 1 * from #temp3
)
insert into #final ( col1 , col2, col3 )
select col1, col2, col3 from cfinal
delete from #temp1 where id in (select top 3 ID from #temp1)
delete from #temp2 where id in (select top 2 ID from #temp2)
delete from #temp3 where id in (select top 1 ID from #temp3)
set #i = #i+1
End
Select * from #final
Drop table #temp1
Drop table #temp2
Drop table #temp3
GO
First create temp table for all 3 tables with each insert delete the inserted record and this will result you the desired result, if nothing is missing from my side.
Please see to this if this works.
There is not a lot of information to go with here, but I assume you can use UNION to combine multiple statements.
SELECT * TableA ORDER BY ID DESC OFFSET 3 ROWS
UNION
SELECT * TableB ORDER BY ID DESC OFFSET 2 ROWS
UNION
SELECT * TableC ORDER BY ID DESC OFFSET 1 ROWS
Execute and see if this works.
/AF
From my understanding, I create three temp tables as ta, tb, tc.
select * into #ta from (
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
) a
select * into #tb from (
select 'B' b
union all
select 'B'
union all
select 'B'
union all
select 'B'
union all
select 'B'
) b
select * into #tc from (
select 'C' c
union all
select 'C'
union all
select 'C'
union all
select 'C'
union all
select 'C'
) c
If tables match you tables, then the output looks like A,A,A,B,B,C,A,A,A,B,B,C,A,B,C,C,C
T-SQL
declare #TAC int = (select count (*) from #ta) -- Table A Count = 7
declare #TBC int = (select count (*) from #tb) -- Table B Count = 5
declare #TAR int = #TAC % 3 -- Table A Reminder = 1
declare #TBR int = #TBC % 2 -- Table B Reminder = 1
declare #TAQ int = (#TAC - #TAR) / 3 -- Table A Quotient = (7 - 1) / 3 = 2, is will passed on NTILE
-- So we gonna split as two group (111), (222)
declare #TBQ int = (#TBC - #TBR) / 2 -- Table B Quotient = (5 - 1) / 2 = 2, is will passed on NTILE
-- So we gonna split as two group (11), (22)
select * from (
select *, NTILE (#TAQ) over ( order by a) FirstOrder, 1 SecondOrder from (
select top (#TAC - #TAR) * from #ta order by a
) ta -- 6 rows are obtained out of 7.
union all
select *, #TAQ + 1, 1 from (
select top (#TAR) * from #ta order by a desc
) ta -- Remaining one row is obtained. Order by desc is must
-- Here FirstOrder is next value of previous value.
union all
select *, NTILE (#TBQ) over ( order by b), 2 from (
select top (#TBC - #TBR) * from #tb order by b
) tb
union all
select *, #TBQ + 1, 2 from (
select top (#TBR) * from #tb order by b desc
) tb
union all
select *, ROW_NUMBER () over (order by c), 3 from #tc
) abc order by FirstOrder, SecondOrder
Let me explain the T-SQL:
Before that, FYR: NTILE and Row Number
Get the count.
Find the Quotient which will pass to NTILE function.
Order by the NTILE value and static.
Note:
I am using SQL Server 2017.
If T-SQL works fine, then you need to change the column in order by <yourcolumn>.

Add A,B,C letters to Duplicate values

I need big help from you I am using sql server 2008 and I want to get the output using sql query.
I have a following data in the table.
Id Code
-----------------
1 01012
2 01012
3 01012
4 01012
5 01013
6 01013
7 01014
I need Following output
Id Code
-----------------
1 01012
2 01012A
3 01012B
4 01012C
5 01013
6 01013A
7 01014
You can use ROW_NUMBER. When Rn = 1, retain the original Code else, add A, B, and so on.
To determine which letter to add, the formula is CHAR(65 - RN - 2).
WITH CTE AS(
SELECT *,
Rn = ROW_NUMBER() OVER(PARTITION BY Code ORDER BY Id)
FROM tbl
)
SELECT
Id,
Code = CASE
WHEN Rn = 1 THEN Code
ELSE Code + CHAR(65 + Rn - 2)
END
FROM CTE
SQL Server 2012+ Solution
Can be adpated to 2008 be replacing CONCAT with + and CHOOSE with CASE.
Data:
CREATE TABLE #tab(ID INT, Code VARCHAR(100));
INSERT INTO #tab
SELECT 1, '01012'
UNION ALL SELECT 2, '01012'
UNION ALL SELECT 3, '01012'
UNION ALL SELECT 4, '01012'
UNION ALL SELECT 5, '01013'
UNION ALL SELECT 6, '01013'
UNION ALL SELECT 7, '01014';
Query:
WITH cte AS
(
SELECT ID, Code,
[rn] = ROW_NUMBER() OVER(PARTITION BY Code ORDER BY id)
FROM #tab
)
SELECT
ID,
Code = CONCAT(Code, CHOOSE(rn, '', 'A', 'B', 'C', 'D', 'E', 'F')) -- next letters
FROM cte;
LiveDemo
select
case
when rownum > 1 then code + char(65+rownum-2)
else code
end as code,
id
from (
select *,
ROW_NUMBER() over( partition by code order by code) as rownum
from #tab
)c

SQL to get an ordinal index in selection for specific ID

I'm working with the SQL Server database. Say, I have a selection that returns an array of IDs. Can I find out (with SQL) the order of an ID equalled N in that array?
Here's what I mean. This is my actual selection:
SELECT [id] FROM [dbo.test_db_002] t1
LEFT JOIN [dbo.test_db_003] t2
ON t1.[id]=t2.[itmid]
ORDER BY t2.[iid] ASC;
Say, it will return the following array of IDs:
13, 7, 34, 5, 2, 14
And, say I need to know what index is ID=5 in that array (the answer is 3, if 13 is index 0, 7 = index 1, 34 = index 2, 5 = becomes index 3.)
Try using ROW_NUMBER():
SELECT ROW_NUMBER() OVER (ORDER BY t2.[iid] ASC) -1 AS RowIndex
,[id]
FROM [dbo.test_db_002] t1
LEFT JOIN [dbo.test_db_003] t2
ON t1.[id]=t2.[itmid]
ORDER BY t2.[iid] ASC;
More on it here http://msdn.microsoft.com/en-us/library/ms186734.aspx
Try this:
SELECT x.RowNum - 1
FROM
(
SELECT [id], ROW_NUMBER() OVER (ORDER BY t2.[iid]) as RowNum
FROM [dbo.test_db_002] t1
LEFT JOIN [dbo.test_db_003] t2 ON t1.[id]=t2.[itmid]
) x
WHERE x.[id] = 5
Note that the -1 is because ROW_NUMBER() starts at 1 instead of 0 and you specifically mentioned a zero-indexed array.
Try this... Though I'm not sure on your table structure
Declare #Temp table
(
id int,
Name varchar(20)
)
Insert into #Temp
select 1, 'Bob'
union all
select 2, 'Mark'
union all
select 3, 'Shaun'
union all
select 4, 'Ryan'
union all
select 5, 'Steve'
union all
select 6, 'Bryan'
union all
select 7, 'Henry'
Declare #Temp2 table
(
iid int,
itmid int,
Name varchar(20)
)
Insert into #Temp2
select 1, 3, 'Thing'
union all
select 2, 2, 'This'
union all
select 3, 5, 'That'
union all
select 4, 1, 'They'
union all
select 5, 3, 'There'
union all
select 6, 5, 'Though'
union all
select 7, 6, 'Thought'
SELECT t1.[id], Row_Number() OVER (Order by t1.[id]) as RowNum
FROM #Temp t1
LEFT JOIN #Temp2 t2 ON t1.[id]=t2.[itmid]
ORDER BY t1.[id] ASC;

Is it possible to Union the result sets of two CTEs with identical structure

I want to union the results sets from the following CTEs so that I get 4 rows of data.
Id Name
-------------
1 Test1
2 Test2
3 Test3
4 Test4
The Sql I want to use is as follows
;with CTE1 (Id,Name)
as
(
select 1 as Id, 'Test1' as Name
union all
select 2, 'Test2'
)
select * from CTE1
union all
;with CTE2 (Id,Name)
as
(
select 3 as Id, 'Test3' as Name
union all
select 4, 'Test4'
)
select * from CTE2
However, I am getting a syntax error suggesting I can not use Union All between the two CTEs.
How can I go around this?
YES, but not the way you are doing it. try it this way:
;with CTE1 (Id,Name)
as
(
select 1 as Id, 'Test1' as Name
union all
select 2, 'Test2'
)
,CTE2 (Id,Name)
as
(
select 3 as Id, 'Test3' as Name
union all
select 4, 'Test4'
)
select * from CTE1
union all
select * from CTE2
you can have multiple CTEs chained together. There is only one "WITH", and a comma between CTEs. Then in the statement following the CTE, you can reference any of those CTEs.
;with CTE1 (Id,Name)
as
(
select 1 as Id, 'Test1' as Name
union all
select 2, 'Test2'
)
,CTE2 (Id,Name)
as
(
select 3 as Id, 'Test3' as Name
union all
select 4, 'Test4'
)
select * from CTE1
union all
select * from CTE2
with CTE1 (Id,Name)
as
(
select 1 as Id, 'Test1' as Name
union all
select 2, 'Test2'
),
CTE2 (Id,Name)
as
(
select * from CTE1
union all
select 3 as Id, 'Test3' as Name
union all
select 4, 'Test4'
)
select * from CTE2
or
with CTE1 (Id,Name)
as
(
select 1 as Id, 'Test1' as Name
union all
select 2, 'Test2'
),
CTE2 (Id,Name)
as
(
select 3 as Id, 'Test3' as Name
union all
select 4, 'Test4'
)
select * from CTE1
union all
select * from CTE2