SQL Server Custom sorting in ORDER BY clause - sql

ALTER PROCEDURE sp_1
AS
BEGIN
SELECT B.ID, 'B' AS Name
FROM tableB inner join table a inner join table c
UNION
SELECT A.ID, 'A' AS NAME
FROM tableA inner join table b inner join table c
UNION
SELECT C.ID, 'C' AS NAME
FROM tableC inner join table a inner join table b
ORDER BY CASE WHEN Name = 'A' THEN '1'
ELSE Name END ASC
END
The code above returns invalid column name 'Name'. Is there anyway where i can sort 'name customly by using order by without delcaring any new paramters.

SELECT B.ID, 'B' AS Name, 1 as ExplicitOrderGroup
FROM tableB inner join table a inner join table c
UNION
SELECT A.ID, 'A' AS NAME, 0 as ExplicitOrderGroup
FROM tableA inner join table b inner join table c
UNION
SELECT C.ID, 'C' AS NAME, 1 as ExplicitOrderGroup
FROM tableC inner join table a inner join table b
ORDER BY ExplicitOrderGroup, Name
Note, UNION (which behaves a bit like DISTINCT) will not collaps now same rows with different ExplicitOrderGroup. You have to determine whethere it's OK or you need some other behaviour.

You can't use alias in order by you have to use concrete column but you can achieve this easily using common table expression for example
WITH MY_CTE (col1, col2, col3)
AS
-- Define the CTE query.
(
SELECT col1, prop2 as col2, col3
FROM table
)
-- Define the outer query referencing the CTE name.
SELECT col1, col2, col3
FROM MY_CTE
ORDER BY col2
GO
This is just an example to point u in direction

Can achieve this by sub-query without any new variable/parameter
ALTER PROCEDURE sp_1
AS
BEGIN
SELECT SQ.ID, SQ.Name FROM (
SELECT B.ID, 'B' AS Name
FROM table B inner join table a inner join table c
UNION
SELECT A.ID, 'A' AS NAME
FROM table A inner join table b inner join table c
UNION
SELECT C.ID, 'C' AS NAME
FROM table C inner join table a inner join table b
) SQ
ORDER BY CASE WHEN SQ.Name = 'A' THEN '1'
ELSE SQ.Name END ASC
END

In this case I would add an extra column for priority.
Like this:
ALTER PROCEDURE sp_1
AS
BEGIN
SELECT B.ID, 'B' AS Name, 2 AS prio
FROM tableB inner join table a inner join table c
UNION
SELECT A.ID, 'A' AS NAME, 1 AS prio
FROM tableA inner join table b inner join table c
UNION
SELECT C.ID, 'C' AS NAME, 2 AS prio
FROM tableC inner join table a inner join table b
ORDER BY prio ASC, Name ASC
END

Related

Get exclusive users in each table

I have 4 tables as shown below
For each table I want the count of users that are present exclusively in that table (not present in other tables). The result should look something likes this
I have one way of getting desired result as shown below:
First Column:
SELECT COUNT(DISTINCT A.id) table1_only
FROM table1 A
LEFT JOIN (SELECT DISTINCT id
FROM table2
UNION
SELECT DISTINCT id
FROM table3
UNION
SELECT DISTINCT id
FROM table4) B
ON A.id = B.id
WHERE B.id IS NULL
Second Column:
SELECT COUNT(DISTINCT A.id) table2_only
FROM table2 A
LEFT JOIN (SELECT DISTINCT id
FROM table1
UNION
SELECT DISTINCT id
FROM table3
UNION
SELECT DISTINCT id
FROM table4) B
ON A.id = B.id
WHERE B.id IS NULL
Third Column:
SELECT COUNT(DISTINCT A.id) table3_only
FROM table3 A
LEFT JOIN (SELECT DISTINCT id
FROM table1
UNION
SELECT DISTINCT id
FROM table2
UNION
SELECT DISTINCT id
FROM table4) B
ON A.id = B.id
WHERE B.id IS NULL
Fourth Column:
SELECT COUNT(DISTINCT A.id) table4_only
FROM table4 A
LEFT JOIN (SELECT DISTINCT id
FROM table1
UNION
SELECT DISTINCT id
FROM table2
UNION
SELECT DISTINCT id
FROM table3) B
ON A.id = B.id
WHERE B.id IS NULL
But I wanted to know if there is any efficient and scalable way to get same result. Just for 4 tables the amount of code is too much.
Any ways of optimizing this task will be really helpful.
Sample fiddle. (This fiddle is for mysql, I am looking for a generic SQL based approach than any db specific approach)
P.S.:
There is no complusion on the result needs to be in column wise. It can be row wise as well, as shown below:
I would approach this by combining the data from all tables. Then aggregate and filter:
select which, count(*) as num_in_table_only
from (select id, min(which) as which, count(*) as cnt
from ((select id, 1 as which from table1) union all
(select id, 2 as which from table2) union all
(select id, 3 as which from table3) union all
(select id, 4 as which from table4)
) t
group by id
) i
where cnt = 1
group by which
Note: In your sample data, the ids are unique in each table. This solution assumes that is true, but can easily be tweaked to handle duplicates within a table.

Join tables that might not have records

I have two tables, tableA which has a list of records and tableB which has restrictions (if any). How can I join the tables that will essentially be an inner join if there are records in tableB or no join if tableB is empty?
ie:
tableA
id | name
1 | val1
2 | val2
tableB (with restrictions)
id | name | userID
1 | val1 | 123
OR tableB (no restrictions)
id | name | userID
is this possible? My attempt below:
SELECT a.*
FROM tableA a
INNER JOIN (CASE WHEN select 1 from tableB = 1 THEN tableB ELSE tableA END) b
ON a.id = b.id
where userID = XXX
EDIT: There is a check on tableB
Just use a left join
SELECT a.*
FROM tableA a
LEFT JOIN tableB b = ON a.id = b.id and b.userid = xxx
I'm not seeing any complexity beyond that at present - given the simplicity of the statement in the original question, I am wondering if you are putting WHERE predicates against the table B - if you are, they need to be in the ON clause of the join
Edited to include your where clause moved.
For empty rows, u can use same query for both restrictions.
I guess you are usign SQL server
Use left join to pull rows if table b is blank
select a.id,a.name
from tableA a left join tableB on a.id = b.id
Demo:
declare #tableA table (id int, name varchar(10))
insert into #tableA
select 1, 'name'
union all
select 2,'name1'
union all
select 3,'name2'
declare #tableb table (id int, name varchar(10))
select a.id,a.name
from #tableA a left join #tableb b on a.id = b.id
this will pull all records from tableA if tableB is empty and only matching records if it is not:
select a.id, a.name
from tableA a
join tableB on a.id = b.id
where exists (select 1 from tableB)
union all
select a.id, a.name
from tableA a
where not exists (select 1 from tableB)

Is there a way to JOIN a table consisting of two tables UNIONed together?

SELECT
a.First_Name
,b.Last_Name
FROM table a
JOIN table b
UNION table c
ON a.ID=b.ID
I'm not even sure how the syntax would be for this. Basically what I want is to UNION table b and c then JOIN the new table to table a.
You can join a subquery:
SELECT
a.First_Name,
bc.Last_Name
FROM a
JOIN
(
SELECT ID, Last_Name FROM b
UNION
SELECT ID, Last_Name FROM c
) bc ON bc.ID = a.ID;
Make the union a subquery:
SELECT
a.First_Name
,bc.Last_Name
FROM table a
JOIN (
SELECT * FROM table b
UNION
SELECT * FROM table c
) AS bc
ON a.ID=bc.ID
Note that the subquery must have its own alias (bc in this case) which should be referenced in the join clause and the select (meaning you can't reference tables b or c directly outside of the subquery).
The result of a union can be join to others table if you the the proper join clause
You could use this sintax
select a.col1, t.name
from table3 c
inner join (
select id, name1 as name
from table1 a
union id, name2
from table2 b
) t on. t.id = a.id

XOR JOIN in SQL

I have the following tables
Table A
ID "Other Columns"
1
2
3
Table B
ID "Other Columns"
3
4
5
What is the efficient way to return the below result?
Result
ID "Other Columns"
1
2
4
5
A full outer join should work, and only go through each table once. They can be tricky, so test carefully!
SELECT
isnull(A.ID, B.ID) ID
,"Other columns" -- Handle nulls properly!
from TableA A
full outer joing TableB B
on B.ID = A.ID
where not (A.ID is not null
and B.ID is not null)
You want to use left and right join and union them
Select TableA.ID as 'ID','Other Colums'
FROM TableA Left join TableB
ON TableA.ID=TableB.ID
WHERE TableB.ID IS NULL
UNION
Select TableB.ID as 'ID','Other Colums'
FROM TableA Right join TableB
ON TableA.ID=TableB.ID
WHERE TableA.ID IS NULL
You can try like this
SELECT
COALESCE(a.id, b.id),
OtherColumns
FROM #tablea a
FULL JOIN #tableb b
ON a.id = b.id
WHERE a.id IS NULL
OR b.id IS NULL
You can do this with a UNION ALL using a LEFT JOIN to determine if the ID is not in the other table. Keep in mind that the column count and datatypes between the two tables must match up:
Select A.Id, A.OtherColumns
From TableA A
Left Join TableB B On A.Id = B.Id
Where B.Id Is Null
Union All
Select B.Id, B.OtherColumns
From TableB B
Left Join TableA A On A.Id = B.Id
Where A.Id Is Null
Not quite sure what you need with the "Other columns", but you could use EXCEPT:
Select ID from TableA
EXCEPT
Select ID from TableB
If you need Other columns from TableA you could use:
Select ID, OtherColumn1, OtherColumn2 from TableA
where ID not in (select ID from TableB)
(as long as ID cannot be null in TableB)
I broke down each part to be clearer!
select *
into #temp
from
TabA Full outer join TabB
on TabA.ColNameA = TabB.ColNameB
select *
into #temp2
from #temp
where (ColNameA is Null Or ColNameB is null)
select ColNameA from #temp2
where ColNameA Is not null
union
select ColNameB from #temp2
where ColNameB Is not null

Table Join condition

I have two tables
Table A :
Item Lookup
A X
B null
C Y
D K
Table B :
Lookup
X
Y
Z
I want to join these tables and get output like
Item Lookup
A X
B null
C Y
I wanna pick up all matching lookup and as well as null lookups in my output view. can anyone tell me the join condition
It looks like you want rows in A that either match B or have a NULL lookup. You would do this with an inner join and a special condition:
select distinct a.item, a.lookup
from tableA a join
tableB b
on (a.lookup = b.lookup) or (a.lookup is NULL);
If you have an index on lookup, then exists is better for performance:
select a.item, a.lookup
from tableA a
where a.lookup is null or
exists (select 1 from tableB b where b.lookup = a.lookup);
EDIT:
Using a left join with a where condition is also possible:
select distinct a.item, a.lookup
from tableA a left join
tableB b
on a.lookup = b.lookup
where (a.lookup is NULL and b.lookup is NULL) or
b.lookup is not null;
The following query will return all records of TableA that have Lookup in TableB, or have a NULL Lookup:
SELECT Item, Lookup
FROM TableA
WHERE (Lookup IS NULL) OR Lookup IN (SELECT Lookup FROM TableB)
I think this will help
SELECT DISTINCT A.Item, A.Lookup FROM A, B WHERE A.lookup=B.lookup OR A.lookup IS NULL
You can do also do it via a left outer join:
with tablea as (select 'A' item, 'X' lookup from dual union all
select 'B' item, null lookup from dual union all
select 'C' item, 'Y' lookup from dual union all
select 'D' item, 'K' lookup from dual),
tableb as (select 'X' lookup from dual union all
select 'Y' lookup from dual union all
select 'Z' lookup from dual)
select a.item,
a.lookup
from tableA a
left outer join tableB b on (a.lookup = b.lookup)
where a.lookup is null
or a.lookup = b.lookup;
ITEM LOOKUP
---- ------
A X
C Y
B