Get only one row from inner join - mysql

I have two tables. Primary key from table A is primary key in table B with another column.
So structure is like this.
Table A
id - PRIMARY
total_amount
Table B
id - PRIMARY
another_id PRIMARY
status
So i can have id from table A appear multiple times in table B.
My problem is that this query
SELECT IFNULL(SUM(total_amount), 0) AS amount
FROM tableA AS a
INNER JOIN tableB AS b
ON a.id = b.id
WHERE a.id = 10
AND status <> 'UNKNOWN'
sometimes returns more in amount the it should.
If total_amount on id 10 is 2, and that same id 10 repeats in table b three times my amount will be 6 instead of 2.
Is there a way I can avoid that. Some other way to write this query.
Thank you.

Use exists instead:
SELECT IFNULL(SUM(total_amount), 0) AS amount
FROM tableA a
WHERE EXISTS (SELECT 1
FROM tableB AS b
WHERE a.id = b.id AND b.status <> 'UNKNOWN'
);

DISTINCT the list of ids returned from tableB
SELECT
IFNULL(SUM(total_amount), 0) AS amount
FROM
tableA AS a INNER JOIN (SELECT DISTINCT id FROM tableB WHERE [status] <> 'UNKNOWN') AS b ON a.id = b.id
WHERE
a.id = 10

Related

I want to update table value based on another table max value

I have two tables A and B(oracle database). Table B has two columns Id and mdate, where id is primary key. Table A has two columns Id and mdate where id is foreign key. I want to update table B mdate value which should be max mdate value from table A for matching Id.
Update b
set mdate= (select max(mdate) from a group by Id)
where b.id = a.id;
You're very close. The WHERE clause needs to be moved into the subquery, to make it a correlated subquery. Also, the parameter to UPDATE is a table name, not a column name.
UPDATE b
SET mdate = (SELECT MAX(mdate) FROM a WHERE b.id = a.id)
In MySQL you can also do it with a JOIN:
UPDATE b
JOIN (SELECT id, MAX(mdate) AS mdate
FROM a
GROUP BY id) AS a ON a.id = b.id
SET b.mdate = a.mdate
Update b
set(b.mdate) = (select MAX(a.mdate) from a where b.id = a.id)
where exists ( select 1 from a where b.id = a.id);
Thanks to Mr. Barmar.

Left join is returning multiple rows from Table B corresponding to ID present in Table A

I have 2 tables in my SQL database. Let's call them Table A and Table B.
I have joined both the tables using left join on ID = AID. Table A has a field by name ID and Table B has field AID and Price.
The problem is Table B can have multiple prices for the ID present in Table A.
The requirement is - If only one price is present in Table B corresponding to ID in table A then it should return that price.
If more than one price is present in table B for an ID in table A then I should get the price as Zero/null.
Query -
SELECT DISTINCT A.ID,B.Price
from A
left join B
on A.ID = B.AID
where "some condition"
Use Count() with Over() window function to find the count of records for each ID then based on count return the price
Try this way
SELECT DISTINCT A.ID,
case when count(1) over(partition by A.ID) > 1 then NULL else B.Price end
from A
left join B
on A.ID = B.AID
For Mysql
SELECT DISTINCT a.id,
CASE
WHEN c.aid IS NULL THEN NULL
ELSE b.price
END
FROM a
LEFT JOIN b
ON a.id = b.aid
LEFT JOIN (SELECT aid
FROM b
GROUP BY aid
HAVING Count(1) = 1) c
ON a.id = c.aid
For SQL Server (should work for MySQL too). One sub-query (you can put in CTE) that shows only AIDs that have only one price:
SELECT A.ID,
B.Price
FROM A
LEFT JOIN (
SELECT AID
FROM B
GROUP BY AID
HAVING COUNT(Price) = 1
) as C
ON C.AID = A.ID
LEFT JOIN B
ON C.AID = B.AID
Use below query. It should work.
SELECT A.ID, o.Price
FROM A
OUTER APPLY
(
SELECT IIF(COUNT(B.Price)>1,NULL,MAX(B.Price)) AS Price
FROM B
WHERE B.AID = A.ID
) AS o;

mysql display field values from subquery

I have following query that works correctly:
select * from myTable a where a.company is null and exists (select b.company from myTable b where b.id = a.id and b.office_id = a.office_id and b.company is not null);
Now, I also want to display the field value b.company from the subquery next to the fields from myTable a.
How do I get this done?
Thank you and best regards
If you want results from multiple tables you should join the tables together.
Since you want only records from A that exist in B, you need to use an outer JOIN returning all records from A and only those matching in B. But then you want to exclude all those records from A that were not found in B.
SELECT *, b.company
FROM myTable a
LEFT JOIN myTable B
ON b.id = a.id
and b.office_id = a.office_id
and b.company_ID is not null
WHERE a.company is null
and B.ID is not null and B.office_ID is not null --this handles the exists part.

SQL Join over two tables

here is my problem:
I have two tables. Every entry of table A has several entries in table B matched over an ID. I now want to get all entries of table A with one data entry of table B - the one with the highest ID in this table.
Table A has an ID
Table B has an own ID and ID_OF_TABLE_A (for the relation between both)
Table A has one to many relation to Table B. I want all Entries of Table A, matched with the one with the highest ID out of B. Is there any way to realize this in an SQL Statement? I tried all kinds of joins since I need the information of that matched entry in the outcome of the select.
How about
SELECT *
FROM tableA a
INNER JOIN tableB b ON a.ID = b.ID_OF_TABLE_A
WHERE b.ID = (SELECT MAX(ID) FROM tableB c WHERE b.ID = c.ID)
Try this:
SELECT a.*, b.*
FROM tableA a
LEFT OUTER JOIN (SELECT b.*
FROM tableB b
INNER JOIN (SELECT ID_OF_TABLE_A, MAX(ID) bID
FROM tableB
GROUP BY ID_OF_TABLE_A
) c ON b.ID_OF_TABLE_A = c.ID_OF_TABLE_A AND b.ID = c.bID
) AS b ON a.ID = b.ID_OF_TABLE_A;
You can use an inline view where you filter the rows you need from table b with the help of the grouping clause and max function like so:
select a.*, b.*
from a
join (
select max(id) as id_b_max, id_a
from b
group by id_a
) b
on a.id = b.id_a;
Tested with:
create table a(id int);
create table b(id int, id_a int);
insert a values (1);
insert b values(1, 1);
insert b values(2, 1);
insert b values(3, 1);
select a.id, max(b.id)
from table_a a join table_b b on a.id = b.table_a_id
group by a.id
This should work. prefilter out the max id of the ID_OF_TABLE_A. and then join on that id.
SELECT A.*, B.*
FROM A
INNER JOIN ( SELECT max( ID ) AS id, ID_OF_TABLE_A
FROM B
GROUP BY ID_OF_TABLE_A) AS grp_b
ON grp_b.ID_OF_TABLE_A = a.ID
INNER JOIN B ON b.ID = grp_b.id

SQL: Joining results of 2 select queries into 1 row

I have this query that will work if there is data in both tables
SELECT a.location, b.location, a.refno, b.note
FROM (
SELECT location, refno
FROM tableA WHERE refno = '1234'
) a, (
SELECT location, note FROM tableB WHERE note = LN1234567
) b
but some of the time there may not be data in either one of the tables for the specific match in the WHERE clauses
I've also tried this which does work but i need the data on one row
SELECT location, refno
FROM tableA
WHERE refno = '1234'
UNION
SELECT location, note
FROM tableB
WHERE note = 'LN1234567'
My question is, is there an alternative way of querying both tables so I get one row with data from either OR both tables?
You can try with:
SELECT MAX(location_a) AS location_a,
MAX(refno_a) AS refno_a,
MAX(location_b) AS location_b,
MAX(refno_b) AS refno_b
FROM (
SELECT location AS location_a,
refno AS refno_a,
NULL AS location_b,
NULL AS refno_b
FROM tableA
WHERE refno = '1234'
UNION ALL
SELECT NULL AS location_a,
NULL AS refno_a,
location AS location_b,
location AS refno_b
FROM tableB
WHERE note = 'LN1234567') s
Assuming you want matching locations on both side, you want a left join. Here is a simplified version:
SELECT a.location, b.location, a.refno, b.note
FROM tableA a LEFT JOIN
tableB b
on a.location = b.location
WHERE a.refno = '1234' and b.note = 'LN1234567';
If you actually want a cross join (different locations on the same row) and still want results, I think you need a union all:
SELECT a.location, b.location, a.refno, b.note
FROM tableA a CROSS JOIN
tableB b
WHERE a.refno = '1234' and b.note = 'LN1234567'
UNION ALL
SELECT a.location, NULL, a.refno, NULL
FROM tableA
WHERE NOT EXISTS (SELECT 1 FROM tableB b WHERE b.note = 'LN1234567');