Suppose I have a table a with columns A1,A2,A3,A4 and table b with columns B1,B2,B3,B4.
I want to find a records which are having different values in column A1,A2 and B1,B2
Ex.
A1 A2 A3 A4 B1 B2 B3 B4
12 10 10 12 12 10 10 12
14 14 10 12 15 10 10 12
15 10 10 10 15 10 10 10
IT SHOULD RETURN
14 14 10 10
I tried:
SELECT A1,A2
FROM A
EXCEPT
SELECT B1,B2
FROM B;
However, it returned on A1,A2 columns instead of all columns
use left join
select a.* from tableA a
left join tbaleB b
on a.A1=b.B1 and a.A2=b.B2 and a.A3=b.B3 and a.A4=b.B4
where b.B1 is null
You can try below using left join
select * from tableA
left join tableB on A1=B1 and A2=B2
where B1 is null and B2 is null
I would use not exists:
select a.*
from a
where not exists (select 1
from b
where a.a1 = b.b1 and a.a2 = b.b2
);
Related
If I have TABLE_A:
A_ID B_ID
1 6
2 6
3 7
4 7
5 7
and TABLE_B:
B_ID B_NAME
6 B1
7 B2
8 B3
9 B4
How can I find the number of occurrences of B_ID in TABLE_A? Something like this:
select B_ID, B_NAME, total_count from TABLE_B
Where "total_count" is the number of times B_ID is found in TABLE_A so that the result would be:
B_ID B_NAME total_count
6 B1 2
7 B2 3
8 B3 0
9 B4 0
Use group by, left join and count:
SELECT B.B_ID, B.B_NAME, COUNT(A.A_Id) As TotalCount
FROM TableB As B
LEFT JOIN TableA As A
ON B.B_ID = A.B_ID
GROUP BY B.B_ID, B.B_NAME
This is quite a basic query in SQL, and should produce the same result on most if not all relational databases.
I have 5 tables A, A1, A2, A3, A4.
A has the foreign key relationship with remaining 4 tables.
I want order A by first checking availability in A1 first then in A2 and so on.
So results should be displayed in order by it's availability in A1, A2, A3, A4.
select * from A as main
order by (select abc from A1 where main.abc = A1.abc), (select abc from A2 where main.abc = A2.abc), (select abc from A3 where main.abc = A3.abc), (select abc from A4 where main.abc = A4.abc)
if there are 10 records in A table then i want all 10 records in result but that records should be ordered by it's availability in A1, A2, A3 and A4
little help will be appreciated.
Use LEFT JOIN and COALESCE
select distinct A.*
from A
LEFT JOIN A1 ON A.abc = A1.abc
LEFT JOIN A2 ON A.abc = A2.abc
LEFT JOIN A3 ON A.abc = A3.abc
LEFT JOIN A4 ON A.abc = A4.abc
ORDER BY COALESCE(A1.abc,A2.abc,A3.abc,A4.abc)
However, it does not make much sense. The ordering will be according to the abc value. If you intend to order according to some value in A1 - A4, then use it instead of abc in COALESCE.
If you want rows being in A1 first then you might employ || to enforce ordering according to A1 - A4 existence (if the abc attribute is varchar)
select distinct A.*
from A
LEFT JOIN A1 ON A.abc = A1.abc
LEFT JOIN A2 ON A.abc = A2.abc
LEFT JOIN A3 ON A.abc = A3.abc
LEFT JOIN A4 ON A.abc = A4.abc
ORDER BY COALESCE('a' || A1.abc, 'b' || A2.abc, 'c' || A3.abc, 'd' || A4.abc)
You can sort on EXISTance:
-- sample data
CREATE TABLE a ( abc integer not null primary key);
INSERT INTO a(abc)
select generate_series(1,25);
CREATE TABLE a2 AS select * FROM a where abc %2 = 0;
CREATE TABLE a3 AS select * FROM a where abc %3 = 0;
CREATE TABLE a5 AS select * FROM a where abc %5 = 0;
CREATE TABLE a7 AS select * FROM a where abc %7 = 0;
ALTER TABLE a2 ADD primary key(abc);
ALTER TABLE a3 ADD primary key(abc);
ALTER TABLE a5 ADD primary key(abc);
ALTER TABLE a7 ADD primary key(abc);
-- Query
select * from a
ORDER BY exists (select * from a2 where abc=a.abc) desc
, exists (select * from a3 where abc=a.abc) desc
, exists (select * from a5 where abc=a.abc) desc
, exists (select * from a7 where abc=a.abc) desc
, a.abc -- tie-breaker
;
Result:
CREATE TABLE
INSERT 0 25
SELECT 12
SELECT 8
SELECT 5
SELECT 3
ALTER TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE
abc
-----
6
12
18
24
10
20
14
2
4
8
16
22
15
21
3
9
5
25
7
1
11
13
17
19
23
(25 rows)
Use COALESCE
SELECT A.*
FROM A LEFT JOIN A1 ON A.ID = A1.ID
LEFT JOIN A2 ON A.ID = A2.ID
LEFT JOIN A3 ON A.ID = A3.ID
LEFT JOIN A4 ON A.ID = A4.ID
ORDER BY COALESCE(A1.ID ,A2.ID ,A3.ID ,A4.ID )
I have tables like that: (C1-C2 varchar(10), C3-Number int)
WaitingData
C1 C2 C3 Number
A B 1 10
A B 2 0
A B 3 4
X B 4 2
CompletedData
C1 C2 C3 Number
A B 1 5
A B 2 2
A B 3 0
X B 4 12
I am using the query below to represent the data:
Select wd.C1,wd.C2,wd.C3,wd.Number as NW,cdd.Number as NC
into #AllData
from (Select C1,C2,C3,sum(Number) from WaitingData group by C1,C2,C3) wd
outer apply (Select C1,C2,C3,sum(Number)
from CompletedData cd
where wd.C1=cd.C1 and wd.C2=cd.C2 and wd.C3=cd.C3
) cdd
Select * from #AllData
union
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NW)
from #AllData
This is giving me an output like:
C1 C2 C3 NW NC
A B 1 10 5
A B 2 0 2
A B 3 4 0
X B 4 2 12
Total Total -1 16 19
However, I want to hide the rows that has no NW but calculate its regarding values while calculating the Total row (see NC below). The output I want is like:
C1 C2 C3 NW NC
A B 1 10 5
A B 3 4 0
X B 4 2 12
Total Total -1 16 19
I could not find a way to provide an output like this. Any help would be so appreciated!
------------------------------EDIT---------------------------------------
------------------------------EDIT---------------------------------------
When I have data in the tables like below, the outer apply is not working like I want, it does not include the data A B 2.
WaitingData
C1 C2 C3 Number
A B 1 10
A B 3 4
X B 4 2
CompletedData
C1 C2 C3 Number
A B 1 5
A B 2 2
X B 4 12
And the output would be like:
C1 C2 C3 NW NC
A B 1 10 5
A B 3 4 NULL
X B 4 2 12
Total Total -1 16 17
In this situation, what can I do to count "2" NC value having by A B 2 on the final result and see NC as 19 instead 17, except inserting all the records that included by CompletedData but WaitingData? (need an efficient way)
Wrap the final result with one more select and exclude rows where NW = 0.
select * from
(
Select * from #AllData
union
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NC)
from #AllData
) t
where NW <> 0
Edit: Using a full join to get all values from both tables.
with t as
(select coalesce(w.c1,c.c1) as c1,coalesce(w.c2,c.c2) as c2,coalesce(w.c3,c.c3) as c3
, coalesce(w.number,0) as nw , coalesce(c.number,0) as nc
from waitingdata w
full join completeddata c on w.c1 = c.c1 and w.c2=c.c2 and w.c3=c.c3)
select * from
(select * from t
union all
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NC)
from t) x where nw <> 0
You can do all of this in one query, without temporary tables, intermediate results, subqueries, or UNION by using the ROLLUP operator:
SELECT
WD.C1,
WD.C2,
WD.C3,
SUM(WD.Number) AS NW,
SUM(CD.Number) AS NC
FROM
dbo.WaitingData WD
LEFT OUTER JOIN CompletedData CD ON
CD.C1 = WD.C1 AND
CD.C2 = WD.C2 AND
CD.C3 = WD.C3
GROUP BY
WD.C1,
WD.C2,
WD.C3
WITH ROLLUP
HAVING
GROUPING_ID(WD.C1, WD.C2, WD.C3) IN (0, 7) AND
SUM(WD.Number) <> 0
I have two queries that return:
Query 1
ClassName1 Students1 Teachers1
A1 30 3
A2 20 3
A3 35 4
Query 2
ClassName2 Students2 Teachers2
A1 20 3
A2 22 3
A3 20 4
Result
ClassName1 Students1 Teachers1 ClassName2 Students2 Teachers2
A1 30 3 A1 20 3
A2 20 3 A2 22 3
A3 35 4 A3 20 4
I would like to merge the two dataset into one by columns. SQL 2008
Any ideas?
You would normally do this with a join:
select q1.*, q2.*
from (query1) q1 join
(query2) q2
on q1.ClassName1 = q2.ClassName2;
Thanks i worked this out using this :
**/***********Join **************
select emp.EmpID,emp.FirstName ,emp.LastName,sod.EmpID,sod.HireDate from Employee as emp
join
(
select emp2.EmpID,emp2.HireDate from Employee as emp2
--where emp.EmpID=emp2.EmpID
) sod
on sod.EmpID=emp.EmpID
**/***********cross Apply **************
select emp.EmpID,emp.FirstName ,emp.LastName,sod.EmpID,sod.HireDate from Employee as emp
cross apply
(
select emp2.EmpID,emp2.HireDate from Employee as emp2
where emp.EmpID=emp2.EmpID
) as sod
Any other ideas will be great
Let me try to explain the scenario. I have two tables A (Columns - A1, A2, A3) & B (Columns - B1, B2, B3). I need to join table A with table B on A1.B2. For every join, table B has one or two records with different values for B3(X or Y). I wanna write one query where the JOIN query needs to pick the row with B3=X(if there's no other row with B3=Y); If two rows exists (B3=X & B3=Y), then the query needs to pick only the row with B3=Y (ignoring the row with B3=X).
Let me try to give some values to the tables & explain a little bit more.
Table A
********
A1 A2 A3
1 11 111
2 22 222
3 33 333
4 44 444
Table B
********
B1 B2 B3
6 1 X
7 1 Y
8 2 X
9 3 X
10 3 Y
11 4 X
Again.. JOIN is on A1.B2. The result should be as following,
JOIN Results
*************
A1 A2 A3 B1 B2 B3
1 11 111 7 1 Y
2 22 222 8 2 X
3 33 333 10 3 Y
4 44 444 11 4 X
Let me know if you guys have any clarification about my question.
Thanks in advance.
Yogi
You can pick the rows from table B with the ROW_NUMBER function if you partition by the join column and order by your "picking order" column:
SELECT b1, b2, b3,
ROW_NUMBER() OVER (PARTITION BY b2 ORDER BY b3 DESC) as rn
FROM b;
1 Y 1
1 X 2
2 X 1
3 Y 1
3 X 2
4 X 1
Then you can filter the first row, the one with rn=1:
SELECT b1, b2, b3
FROM (SELECT b1, b2, b3,
ROW_NUMBER() OVER (PARTITION BY b2 ORDER BY b3 DESC) as rn
FROM b)
WHERE rn=1;
7 1 Y
8 2 X
10 3 Y
11 4 X
The filtered rows can then be joined to table a:
SELECT *
FROM a
JOIN (
SELECT b1, b2, b3
FROM (SELECT b1, b2, b3,
ROW_NUMBER() OVER (PARTITION BY b2 ORDER BY b3 DESC) as rn
FROM b
)
WHERE rn=1
) bfilter ON a.a1 = bfilter.b2;
1 11 111 7 1 Y
2 22 222 8 2 X
3 33 333 10 3 Y
4 44 444 11 4 X
If 'X' and 'Y' are not actual values, you can extend the ORDER clause with a CASE statement to allow for general values:
ROW_NUMBER() OVER (PARTITION BY b2 ORDER BY
CASE b3 WHEN 'Y' THEN 1
WHEN 'X' THEN 2
...
END ASC)
Edit:
SELECT a1, a2, a3, b1, b2, b3
FROM (
SELECT a1, a2, a3, b1, b2, b3,
ROWNUMBER() OVER (PARTITION BY a1 ORDER BY
CASE WHEN a2=... AND b3=... THEN 1
WHEN a2=... AND b3=... THEN 2
...
END ASC)
FROM a JOIN b ON a.a1 = b.b2
)
WHERE rn = 1;
You can use left outer joins as follows
select A.A1, A.A2, A.A3,
nvl(BT1.B1, BT2.B1),
nvl(BT1.B2, BT2.B2),
nvl(BT1.B3, BT2.B3) from A
left outer join B BT1 on A.A1 = BT1.B2 and BT1.B3 = 'Y'
left outer join B BT2 on A.A1 = BT2.B2 and BT2.B3 = 'X'
A good explanation of the various joins is at http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
Here is, how I would do it:
Make the join
group by B2
take the max(B3)
That way you ensure that X is only picked, when there is no alphabetically higher value (Y) available
With UNION
select a.*,b.* from a,b
where a.a1=b.b2
and b.b3='Y'
union
select a.*,b.* from a,b
where a.a1=b.b2
and not exists (select bb.br from b bb where bb.b2=a.a1 and bb.b3='Y')
Without UNION
select a.*,b.* from a,b
where a.a1=b.b2
and (b.b3='Y'
or not exists (select bb.b3 from b bb where bb.b2=a.a1 and bb.b3='Y'))
The constraint here is that B has exactly 1 or 2 rows for each A's row