SQL , get difference b/w to id's - mysql

I want to get result from two tables:
Table A
create table A
( propertyId int not null
,PRIMARY KEY (propertyId))
Table B
create table B
( Id int not null
, propertyId int
, FOREIGN KEY (propertyId ) REFERENCES A(propertyId))
Now I want to get the result total count id of Table A exist in Table B AND total count id that does not exist in Table B
SELECT COUNT(property.propertyId) AS 'Occupied'
,(
SELECT COUNT(property.propertyId)
FROM property
INNER JOIN agreement ON property.`propertyId` <> agreement.`propertyId`
) AS 'Vacant'
FROM property
INNER JOIN agreement ON property.`propertyId` = agreement.`propertyId`
WHERE agreement.`isActive` = '1'

You can do a Left join to get the proper result.
select
sum (
case when a.propertyId is not null then 1
else 0
end
) as present_cnt,
sum (
case when a.propertyId is null then 1
else 0
end
) as not_present_cnt
from property p
left join agreement a on p.propertyId = a.propertyId
where a.isActive = '1';
left join will fetch data for a.propertyId from agreement corresponding to p.propertyId, if no match found then null

Your solution should be based on this principle, also exemplified in this SQLFiddle:
SELECT count(CASE
WHEN propertyID IS NOT NULL
AND fk_propertyID IS NOT NULL
THEN 1
ELSE NULL
END) 'exist_in_both_tables'
,count(CASE
WHEN propertyID IS NOT NULL
AND fk_propertyID IS NULL
THEN 1
ELSE NULL
END) 'does_not_exist_in_b'
FROM (
SELECT *
FROM tablea a
LEFT JOIN tableb b ON a.propertyID = b.fk_propertyID
UNION
SELECT *
FROM tablea a
RIGHT JOIN tableb b ON a.propertyID = b.fk_propertyID
) result
You need to duplicate your query and use both LEFT and RIGHT joins and UNION the results of those two separate queries to simulate the result of a FULL JOIN.
After simulating this, you need to go over this result set again, by making this a sub-query and then using aggregate functions, COUNT(), along with CASE statements to count how many matches you have in both tables.
Hence, your final queries should look something like this:
SELECT count(CASE
WHEN Property_PropertyID IS NOT NULL
AND Agreement_PropertyID IS NOT NULL
THEN 1
ELSE NULL
END) 'Occupied'
,count(CASE
WHEN Property_PropertyID IS NOT NULL
AND Agreement_PropertyID IS NULL
THEN 1
ELSE NULL
END) 'Vacant'
FROM (
SELECT property.propertyID 'Property_PropertyID'
FROM property
LEFT JOIN agreement ON property.`propertyId` = agreement.`propertyId`
WHERE agreement.`isActive` = '1'
UNION
SELECT agreement.propertyID 'Agreement_PropertyID'
FROM property
RIGHT JOIN agreement ON property.`propertyId` = agreement.`propertyId`
WHERE agreement.`isActive` = '1'
) ResultSet

Related

mySql - search rows without reference in second table

I have 2 tables.
How do i search for all rows in the first table that has no reference in the second table.
The connection field is: res_srvs.id = inv_supp2srv.srvID
So, I want to get all table "res_srvs" rows that has no srvID in table "inv_supp2srv".
TABLE: res_srvs
Collation Attributes
id int(11)
clientID int(6)
resNum int(9)
net decimal(7,2)
tax decimal(7,2)
from_date(date)
TABLE: inv_supp2srv
Collation Attributes
clientID int(6)
invNum int(10)
srvID int(11)
amount decimal(7,2)
valid tinyint(1)
This is what i tried:
SELECT srv.net , srv.tax , srv.net+srv.tax AS amount, srv.id AS srv_id
FROM res_srvs AS srv , inv_supp2srv AS i2s
WHERE srv.clientID = 1
AND srv.from_date >= '2020-03-01'
AND i2s.clientID = 1
AND i2s.srvID = srv.id
AND (NOT EXISTS
(
SELECT *
FROM inv_supp2srv AS i2s
WHERE i2s.srvID = srv.id
)
)
What you want is a left outer join with exclusion :
SELECT r.*
FROM res_srvs r
LEFT JOIN inv_supp2srv i
ON r.id = i.srvID
WHERE i.srvID IS NULL
AND (
-- Your others where clauses go there
);
You can use LEFT JOIN for second table and filter by NULL joined value like:
SELECT srv.net , srv.tax , srv.net+srv.tax AS amount, srv.id AS srv_id
FROM res_srvs AS srv
LEFT JOIN inv_supp2srv AS i2s ON i2s.srvID = srv.id
WHERE
srv.clientID = 1
AND srv.from_date >= '2020-03-01'
-- AND i2s.clientID = 1 not relevant condition
AND i2s.srvID IS NULL;
Another approach is using NOT EXISTS condition:
SELECT srv.net , srv.tax , srv.net+srv.tax AS amount, srv.id AS srv_id
FROM res_srvs AS srv
WHERE
srv.clientID = 1
AND srv.from_date >= '2020-03-01'
AND NOT EXISTS (
SELECT srvID FROM inv_supp2srv AS i2s WHERE i2s.srvID = srv.id
);
I want to get all table res_srvs rows that have no srvID in table inv_supp2srv.
It looks like you are overcomplicating this. I don't see the point for the join between the tables in the outer query - it attempts to match the tables, which contradicts the not exists condition.
I think you just want:
select r.*
from res_srvs r
where
r.from_date >= '2020-03-01'
and r.clientID = 1
and not exists (
select 1
from inv_supp2srv i
where i.srvID = r.id and i.clientID = r.clientID
)
I am unsure whether you want clientID in the correlation clause or not - your query makes it look like it is the case, so I added it.

Whats wrong with this query? i am getting null result

SELECT `acart`.`order_number` AS `admin_order_number`,
`acart`.`user_id` AS `admin_user_id`,
`acart`.`created_by` AS `admin_created_by`,
`rcart`.`order_number` AS `renew_order_number`,
`rcart`.`user_id` AS `renew_user_id`,
`rcart`.`created_by` AS `renew_created_by`,
`scart`.`order_number` AS `shopping_order_number`,
`scart`.`user_id` AS `shopping_user_id`,
`scart`.`created_by` AS `shopping_created_by`
FROM `cdp_order_transaction_master` AS `master`
LEFT JOIN `cdp_admin_shopping_cart` AS `acart`
ON `acart`.`order_number`=`master`.`order_number`
LEFT JOIN `cdp_renew_cart` AS `rcart`
ON `rcart`.`order_number`=`master`.`order_number`
LEFT JOIN `cdp_shopping_cart` AS `scart`
ON `scart`.`order_number`=`master`.`order_number`
WHERE master.order_number IS NULL
Let me explain my problem,if the order is successfull then it will goes to cdp_order_transaction_master table and any other 3 table (cdp_admin_shopping_cart,cdp_renew_cart,cdp_shopping_cart) depending on the situation but if the order fails then it will not go to cdp_order_transaction_master table and remain in other tables,
so i want the failed order which is not present in cdp_order_transaction_master and can present in any other tables(cdp_admin_shopping_cart,cdp_renew_cart,cdp_shopping_c‌​art)
WHERE master.order_number IS NULL
This is your primary table, and the join condition for all other tables are on this column.
You are trying to join null to null
Based on your comment, try:
select 'cdp_admin_shopping_cart' as `err_table`, a1.order_number
from cdp_admin_shopping_cart a1
where not exists (select 1 from cdp_order_transaction_master a2 where a2.order_number = a1.order_number)
union all
select 'cdp_renew_cart' as `err_table`, a1.order_number
from cdp_renew_cart a1
where not exists (select 1 from cdp_order_transaction_master a2 where a2.order_number = a1.order_number)
union all
select 'cdp_shopping_c‌​art' as `err_table`, a1.order_number
from cdp_shopping_c‌​art a1
where not exists (select 1 from cdp_order_transaction_master a2 where a2.order_number = a1.order_number)

MYSQL SELECT is slow when crossing multiple tables

I have a mysql query which is to return the only 1 record that need to cross multiple table. However, the mysql query is slow when executing.
Query:
SELECT *,
(SELECT TreeName FROM sys_tree WHERE TreeId = Mktg_Unit_Booking.ProjectLevelId) AS PhaseName,
(CASE WHEN ProductType = 'U' THEN (SELECT UnitNo FROM prop_unit pu WHERE pu.UnitId = mktg_unit_booking.UnitId)
ELSE (SELECT BayNo FROM prop_car_park pcp WHERE pcp.CarParkId = UnitId) END) AS UnitNo,
(SELECT CustomerName FROM mktg_customer mc WHERE mc.CustomerId = mktg_unit_booking.CustomerId) AS CustomerName
FROM Mktg_Unit_Booking
WHERE IsDeleted <> '1' AND IsApproved = '1'
AND UnitId = 1110 AND ProductType = 'U'
ORDER BY UnitNo
I have run EXPLAIN in the query and I got this:
Any other suggestion on how to improve the speed of the query?
Thank you!
you are doing the cross product, instead of that you should use join.
Don't use sub-queries in select statement instead use proper join on Mktg_Unit_Booking in after from statement.
you query should something look like :
select
sys_tree.TreeName AS PhaseName,
case
WHEN Mktg_Unit_Booking.ProductType = 'U' then prop_unit.UnitNo
else prop_car_park.BayNo
end as UnitNo,
mktg_customer.CustomerName AS CustomerName
FROM Mktg_Unit_Booking
left join sys_tree on sys_tree.TreeId = Mktg_Unit_Booking.ProjectLevelId
left join prop_unit on prop_unit.UnitId = Mktg_Unit_Booking.UnitId
left join prop_car_park on prop_car_park.CarParkId = Mktg_Unit_Booking.UnitId
left join mktg_customer on mktg_customer.CustomerId = Mktg_Unit_Booking.CustomerId
WHERE IsDeleted <> '1' AND IsApproved = '1'
AND UnitId = 1110 AND ProductType = 'U'
ORDER BY UnitNo;
I have assumed that each table consists of only 1 matching tuple. If there are more then your logic needs to be modified.

Using JOIN and SUM returns unwanted null row when WHERE condition is not met

Please consider the following query:
Select all payments of a user and UNION the results with the user's invoices.
SELECT `id`,
`amount` AS `value`,
'PAYMENT' AS `transaction_type`
FROM `payment`
WHERE `user_id` = $user_id
UNION ALL
SELECT `i`.`id`,
(-1) * SUM(`ii`.`unit_price` * `ii`.`quantity`) AS `value`,
'INVOICE' AS `transaction_type`
FROM `invoice` `i`
JOIN `invoiceitem` `ii` ON `ii`.`invoice_id` = `i`.`id`
WHERE `user_id` = $user_id AND `type` = 'invoice'
The problem is that for users that have no payment and no invoice, an unwanted row is returned like this:
id | value | transaction_type
=================================
NULL | 0 | NULL
But for users that have some data, the result is completely expected.
IMPORTANT EDIT
After some more research, I got that the problem should be from the second subquery below:
SELECT i.id,
(-1) * SUM(ii.unit_price * ii.quantity) AS `value`,
'INVOICE' AS `trans_type`
FROM invoice i
JOIN invoiceitem ii ON ii.invoice_id = i.id
WHERE user_id = 4 AND type = 'invoice'
which returns the following:
id | value | transaction_type
=================================
NULL | NULL | INVOICE
Of course the user with user_id = 4 has not yet any invoice. But for another user that has some invoices, the result is OK.
This row is created by the aggregate function SUM. In order to prevent this, use a valid GROUP BY clause, probably GROUP BY user_id
It's impossible to say with any certainty without understanding the complete table descriptions, but based on the update to your question, you need to eliminate rows that have NULL values for the column i.id:
SELECT i.id
, (-1) * SUM(ii.unit_price * ii.quantity) AS `value`
, 'INVOICE' AS `trans_type`
FROM invoice i
JOIN invoiceitem ii
ON ii.invoice_id = i.id
WHERE user_id = 4
AND type = 'invoice'
AND i.id IS NOT NULL
I'm guessing that there is a logical defect in your data model or there might be some other column you should use. I can speculate that this invoice row could be a cancelled order, but it is clear that a row exists where the id column is null, which is why it appears in the result.
To avoid such nulls just use a LEFT JOIN instead of INNER JOIN, so, replace your following sql line:
JOIN `invoiceitem` `ii` ON `ii`.`invoice_id` = `i`.`id`
for this one:
LEFT OUTER JOIN `invoiceitem` `ii` ON `ii`.`invoice_id` = `i`.`id`

Mapping table MySQL / Access

I have a short access/mySQL question. I have a mapping table on the format below.
ID Category_A Category_B Category_C Team
1 a b T1
2 a d T2
I have a second table which also includes Category_A, Category_B, and Category_C. I would like to join the Team value to the my second table based on the mappingtable. My problem is that when there is a blank (e.g. ID=2, Category_B) the mapping should assign the T2 to any row that contains Category_A=a and Category_C=d regardless of the value in Category_B.
Can this type of mapping be done?
Grateful for your help!
In MS Access, I think you would need something on the lines of:
SELECT t.ID, m.Team
FROM Team t
INNER JOIN Mapping m
ON (m.Category_C = t.Category_C)
AND (m.Category_B = t.Category_B)
AND (m.Category_A = t.Category_A)
WHERE m.Category_C Is Not Null
AND m.Category_B Is Not Null
AND m.Category_A Is Not Null
UNION ALL
SELECT t.ID, m.Team
FROM Team t
INNER JOIN Mapping m
ON (m.Category_B = t.Category_B)
AND (m.Category_A = t.Category_A)
WHERE m.Category_C Is Null
AND m.Category_B Is Not Null
AND m.Category_A Is Not Null
UNION ALL
SELECT t.ID, m.Team
FROM Team t
INNER JOIN Mapping m
ON (m.Category_C = t.Category_C)
AND (m.Category_A = t.Category_A)
WHERE m.Category_C Is Not Null
AND m.Category_B Is Null
AND m.Category_A Is Not Null
UNION ALL
SELECT t.ID, m.Team
FROM Team t
INNER JOIN Mapping m
ON (m.Category_C = t.Category_C)
AND (m.Category_B = t.Category_B)
WHERE m.Category_C Is Not Null
AND m.Category_B Is Not Null
AND m.Category_A Is Null