Flag row has duplicate value - sql

I have query problem. I have 3 table.
table A
----------------------------
NAME | CODE
----------------------------
bob | PL
david | AA
susan | PL
joe | AB
alfred | PL
table B
----------------------------
CODE | DESCRIPTION
----------------------------
PL | code 1
PB | code 2
PC | code 3
table C
----------------------------
CODE | DESCRIPTION
----------------------------
AA | code 4
AB | code 5
AC | code 6
Table B and C have unique row.
the result I need to flag which row has duplicate records:
-------------------------------------
NAME | CODE | DESCRIPTION | DUPLICATE
-------------------------------------
bob | PL | code 1 | YES
david | AA | code 4 | NO
susan | PL | code 1 | YES
joe | AB | code 5 | NO
Alfred | PL | code 1 | YES
What I have tried so far
http://sqlfiddle.com/#!9/ffb2eb/16

I don't see why you need tables B and C at all to calculate the flag. You can do this with window functions:
select a.*,
(case when count(*) over (partition by a.code) > 1 then 'YES' else 'NO'
end) as flag
from a;
You do need B and C if you want to bring in the additional values:
select a.*, coalesce(b.description, c.description) as description,
(case when count(*) over (partition by a.code) > 1 then 'YES' else 'NO'
end) as flag
from a left join
b
on a.code = b.code left join
c
on a.code = c.code;
Here is a working Oracle SQL Fiddle.

Try the below code in MYSQL (http://sqlfiddle.com/#!9/9a149b/1)
Note :- The code works in Oracle as well http://sqlfiddle.com/#!4/6c6df/5
select A.*,
COALESCE(B.DESCRIPTION, C.DESCRIPTION) AS DESCRIPTION,
dup.DUPLICATE
from A
left join B on A.CODE = B.CODE
left join C on A.CODE = C.CODE
INNER JOIN (select a.code,
case when count(a.code) > 1 then 'YES' else 'NO' end as
DUPLICATE
from A
group by a.code) dup
ON A.code=dup.code

Related

Get left table data completely even when there is no reference in right joined table

Database used: SQL Server
I have three tables A,B,C.
TABLE A:
------------------
| ID | Name |
------------------
| 1 | X |
------------------
| 2 | Y |
------------------
TABLE B:
----------------------
| ID | Date |
----------------------
| 1 | 2019-11-06 |
----------------------
| 2 | 2019-11-05 |
----------------------
TABLE C:
----------------------------------
| ID | B.ID | A.ID | Amount |
----------------------------------
| 1 | 1 | 1 | 500 |
----------------------------------
| 2 | 2 | 2 | 1000 |
----------------------------------
The result I would like to get is all entries of table A.Name with their amount in table C.amount where table B.Date = 2019-11-06. The result set should include all A.name entries even it have no reference in Table C.
Required result is:
-----------------------
| A.Name | C.Amount |
-----------------------
| X | 500 |
-----------------------
| Y | NULL |
-----------------------
Code I tried with :
SELECT A.Name,C.Amount
FROM A
LEFT OUTER JOIN C ON C.A_ID=A.ID
LEFT OUTER JOIN B ON B.ID = C.B_ID ON
WHERE B.Date='2019-11-06'
The result I obtained with above code is :
------------------
| Name | Amount |
------------------
| X | 500 |
------------------
There is no Y in the result, its because there is no entry for Y on that particular date. I just want to show Y and amount as null or zero.
SQL Fiddle with my query
Please help me with this.
There's is no relationship between your A and B, so we need to group B and C using a subquery to filter with date before doing the left join.
SELECT A.Name, t1.Amount
FROM A
LEFT JOIN
(SELECT C.A_ID, C.Amount FROM C
INNER JOIN B ON B.ID = C.B_ID
WHERE B.Date='2019-11-06') t1
ON t1.A_ID=A.ID
see dbfiddle
Try this-
Fiddle Here
SELECT A.Name,C.Amount
FROM A
LEFT JOIN B ON A.ID = B.ID AND B.Date = '2019-11-06'
LEFT JOIN C ON B.ID = C.ID
Output is-
Name Amount
X 500
Y (null)

Combine different table with same column without ambigous

I have query problem. I have 3 table.
table A
----------------------------
NAME | CODE
----------------------------
bob | PL
david | AA
susan | PL
joe | AB
table B
----------------------------
CODE | DESCRIPTION
----------------------------
PL | code 1
PB | code 2
PC | code 3
table C
----------------------------
CODE | DESCRIPTION
----------------------------
AA | code 4
AB | code 5
AC | code 6
Table B and C have unique row.
the result I need :
----------------------------
NAME | CODE | DESCRIPTION
----------------------------
bob | PL | code 1
david | AA | code 4
susan | PL | code 1
joe | AB | code 5
What I have tried so far
http://sqlfiddle.com/#!9/ffb2eb/9
You are close. I think you just need COALESCE():
select A.*, coalesce(B.DESCRIPTION, C.DESCRIPTION) as description
from A left join
B
on A.CODE = B.CODE left join
C
on A.CODE = C.CODE
order by A.NAME;
I think UNION will make this. And additionally It will also remove duplicates if some will exists.
SELECT A.NAME , UN.CODE ,UN.DESCRIPTION
FROM A,
(SELECT CODE,DESCRIPTION FROM B
UNION
SELECT CODE,DESCRIPTION FROM C ) UN
WHERE A.CODE = UN.CODE;

Postgres group by columns and within group select other columns by max aggregate

This is probably a standard problem, and I've keyed off some other greatest-n-per-group answers, but so far been unable to resolve my current problem.
A B C
+----+-------+ +----+------+ +----+------+-------+
| id | start | | id | a_id | | id | b_id | name |
+----+-------+ +----+------+ +----+------+-------+
| 1 | 1 | | 1 | 1 | | 1 | 1 | aname |
| 2 | 2 | | 2 | 1 | | 2 | 2 | aname |
+----+-------+ | 3 | 2 | | 3 | 3 | aname |
+----+------+ | 4 | 3 | bname |
+----+------+-------+
In English what I'd like to accomplish is:
For each c.name, select its newest entry based on the start time in a.start
The SQL I've tried is the following:
SELECT a.id, a.start, c.id, c.name
FROM a
INNER JOIN (
SELECT id, MAX(start) as start
FROM a
GROUP BY id
) a2 ON a.id = a2.id AND a.start = a2.start
JOIN b
ON a.id = b.a_id
JOIN c
on b.id = c.b_id
GROUP BY c.name;
It fails with errors such as:
ERROR: column "a.id" must appear in the GROUP BY clause or be used in an aggregate function Position: 8
To be useful I really need the ids from the query, but cannot group on them since they are unique. Here is an example of output I'd love for the first case above:
+------+---------+------+--------+
| a.id | a.start | c.id | c.name |
+------+---------+------+--------+
| 2 | 2 | 3 | aname |
| 2 | 2 | 4 | bname |
+------+---------+------+--------+
Here is a Sqlfiddle
Edit - removed second case
Case 1
select distinct on (c.name)
a.id, a.start, c.id, c.name
from
a
inner join
b on a.id = b.a_id
inner join
c on b.id = c.b_id
order by c.name, a.start desc
;
id | start | id | name
----+-------+----+-------
2 | 2 | 3 | aname
2 | 2 | 4 | bname
Case 2
select distinct on (c.name)
a.id, a.start, c.id, c.name
from
a
inner join
b on a.id = b.a_id
inner join
c on b.id = c.b_id
where
b.a_id in (
select a_id
from b
group by a_id
having count(*) > 1
)
order by c.name, a.start desc
;
id | start | id | name
----+-------+----+-------
1 | 1 | 1 | aname

SQL query with two columns as foreign keys of the same table

I have two tables
Table A
id ! name ! fk_1_table_B_1 ! fk_2_table_B_2
-------|------|----------------|--------------
1 | John | 1 | 3
2 | Paul | 2 | 1
3 | Anna | 4 | 2
4 | Alan ! 3 | 1
Table B
id | code
-------|------
1 | EN
2 | US
3 | FR
4 | IT
The idea is to obtain the following query
id ! name ! code (fk_1_table_B_1) ! code (fk_1_table_B_2)
-------!------!-----------------------!-----------------
1 | John | EN | FR
2 | Paul | US | EN
3 | Anna | IT | US
4 | Alan ! FR | EN
If Table A had only one FK Column from Table B I would do
SELECT tableA, name, tableB.code
FROM tableA, table B
WHERE tableA.fk_1_table_B_1 = tableB.id
How can I do this with Table A having two columns as FK from B? What should I select in the SELECT?EN
Thanks
You should join to the same table twice, giving it two different aliases:
SELECT a.id, a.name, b1.code, b2.code
FROM tableA a
JOIN tableB b1 ON b1.id = a.fk_1_table_B_1
JOIN tableB b2 ON b2.id = a.fk_2_table_B_2
Note how this query uses ANSI join syntax for better clarity: rather than listing all tables in the FROM clause, it puts each of the aliased tableBs in its own JOIN clause.
Maybe this?
select a.id, a.name,
(select b.code from B b where b.id = a.fk_1_table_B_1),
(select c.code from B c where c.id = a.fk_1_table_B_2),
from A a

Using CASE for a specific situation - How TO

I'm trying to find the proper SQL for the following situation:
Supposed we have two tables:
TABLE A
ID int,
TEXT varchar(200)
TABLE B
ID int,
A_NO int,
B_NO int
Fields named "ID" on both tables can be join to link tables.
The following SQL:
SELECT
A.ID,
B.A_NO,
B.B_NO
FROM
A
LEFT JOIN
B
ON A.ID = B.ID
ORDER BY A.ID, B.A_NO, B.B_NO
gives the following results:
Now, the problem.
What is asked for is to have in the column B_NO a value = 1 for the MIN value of column A_NO and a value = 0 for all the others row with the same A_NO value.
The results below are expected:
Please note that, in this example, we can find two rows for each B_NO value but it is possible to have more than 2 rows.
I have tried to reproduce these results by using a CASE but with no success.
Thanks for you help in advance,
Bouzouki.
Try this using CTE and ROW_NUMBER(); (DEMO)
Please note: I have considered myT as your joined query of A and B tables for demo purpose. So replace myT with as yours A LEFT JOIN B ON A.ID = B.ID.
;with cte as (
select id, a_no, b_no,
row_number() over(partition by id,b_no order by a_no) rn
from myT
)
select id,a_no, case when rn=1 then b_no else 0 end b_no
from cte
order by a_no
--RESULTS FROM DEMO TABLE
| ID | A_NO | B_NO |
-------------------------
| 1031014 | 1 | 1 |
| 1031014 | 2 | 0 |
| 1031014 | 3 | 2 |
| 1031014 | 4 | 0 |
| 1031014 | 5 | 3 |
| 1031014 | 6 | 0 |
| 1031014 | 7 | 4 |
| 1031014 | 8 | 0 |
| 1031014 | 9 | 5 |
| 1031014 | 10 | 0 |
something like
select ID, a_no, b_no,
case when a_no = min_a_no then b_no else 0 end as new_b_no
from
a left join b on a.id = b.id left join
(Select ID, B_no, min(a_no) as min_a_no
from a left join b on a.id = b.id
group by id, b_no) m on a.id = m.id and b.b_no = m.b_no
ORDER BY A.ID, B.A_NO