Hi these two SQL Queries return the same result
SELECT DISTINCT ItemID
FROM Sale INNER JOIN Department
ON Department.DepartmentID = Sale.DepartmentID
WHERE DepartmentFloor = 2
ORDER BY ItemID
SELECT DISTINCT ItemID
FROM Sale
WHERE EXISTS
(SELECT *
FROM Department
WHERE Sale.DepartmentID = Department.DepartmentID
AND DepartmentFloor = 2)
ORDER BY ItemID;
The Subquery Inside the Exists returns True So why doesnt the secod query return the equivalent of
SELECT DISTINCT ItemID
FROM Sale
Which guves a different result from the two above.
You are getting confused by EXISTS().. It occurs on a line by line basis, based on table correlation, not just a single true/false. This line of your subquery is your correlation clause:
Sale.DepartmentID = Department.DepartmentID
It is saying "Only show the Sale.ItemIDs where that ItemID's Sale.DepartmentID is in Department."
It achieves the same function as a join predicate, like in your first query:
FROM Sale S
JOIN Department D on S.DepartmentID = D.DepartmentID --here
Conversely, this query:
SELECT DISTINCT ItemID
FROM Sale
Has no limiting factor.
As an aside, you also further limit the results of each query with:
WHERE DepartmentFloor = 2
But I don't think that is the part that is throwing you off, I think it is the concept that a correlated subquery occurs for each record. If you were to remove your correlating clause, then the subquery would actually return true always, and you would get all results back.
The subquery isn't always returning true. It will evaluate for each row, joining on DepartmentID where the DepartmentFloor is 2.
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Sale ( ItemID int, DepartmentID int ) ;
INSERT INTO Sale ( ItemID, DepartmentID )
VALUES (1,1), (2,2), (3,3), (4,1), (5,4), (6,2), (7,3), (8,4) ;
CREATE TABLE Department ( DepartmentID int, DepartmentFloor int ) ;
INSERT INTO Department ( DepartmentID, DepartmentFloor )
VALUES (1,1), (2,1), (3,2), (4,2) ;
Query 1:
SELECT *
FROM Department
WHERE DepartmentFloor = 2
Results: This lists only the Departments on DepartmentFloor 2.
| DepartmentID | DepartmentFloor |
|--------------|-----------------|
| 3 | 2 |
| 4 | 2 |
Query 2:
SELECT *
FROM Sale
Results: This lists ALL of your Sales.
| ItemID | DepartmentID |
|--------|--------------|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 1 |
| 5 | 4 |
| 6 | 2 |
| 7 | 3 |
| 8 | 4 |
Query 3:
SELECT *
FROM Sale
WHERE DepartmentID IN (3,4)
Results: And this one shows what is the equivalent of you EXISTS statement. It only shows 4 rows that will match up in my data. So you'd only get back ItemIDs 3,5,7 and 8.
| ItemID | DepartmentID |
|--------|--------------|
| 3 | 3 |
| 5 | 4 |
| 7 | 3 |
| 8 | 4 |
because the uppper part of the query is equivalent to
SELECT DISTINCT ItemID FROM Sale where EXISTS (true)
the upper is the only query that really check the condition ..
Related
I want to get the last activity of my client but i dont know how to that that with two tables that have more than one pivot. Please look at to the example below :
table product
--------------------------------------------------------------------------------------------------------------------------------------
id | name | check_mo (Activity1) | check_mo_account_id | check_pa (Activity2) | check_pa_account_id
--------------------------------------------------------------------------------------------------------------------------------------------
1 | product1 | 01/02/2020 | 63 | 05/02/2020 | 100
2 | product2 | 01/03/2020 | 23 | 10/03/2020 | 63
-----------------------------------------------------------------------------------------------------------------------------------
Table account
--------------------------------
id | name
--------------------------------
23 | name1
63 | name2
100 | name3
--------------------------------
I want this result (last activity is the lastest date of (check_mo and check_pa). and relationship between tables is (account.id => product.check_mo_account_id and product.check_pa_account_id))
------------------------------------------------
id | name | last activity
-------------------------------------------------
23 | name1 | 01/03/2020
63 | name2 | 10/03/2020
100 | name3 | 05/02/2020
-------------------------------------------------
Unpivot the columns. In MySQL, you can use union all. Use join to bring in the names and then a window function to get the most recent date:
select pn.*
from (select pn.*, max(dte) over (partition by name) as max_dte
from ((select n.name, p.check_mo as dte, p.check_mo_account_id as account_id
from product p join
name n
on p.check_mo_account_id = n.id
) union all
(select n.name, p.check_pa, p.check_pa_account_id as account_id, p.check_pa
from product p join
name n
on p.check_mo_account_id = n.id
)
) pn
) pn
where dte = max_dte;
If I understand correctly, you have two check IDs and two check dates in one row, but want to treat them equally, just as if you had just one table with one check ID and one check date per row. Use UNION ALL to get this table. Then find the maximum date per ID and join this to the account table.
select id, account.name, aggregated.last_activity
from account
join
(
select id, max(check) as last_activity
from
(
select check_mo_account_id as id, check_mo as check from product
union all
select check_pa_account_id as id, check_pa as check from product
) unioned
group by id
) aggregated using (id)
order by id;
I am a bit new to write complex SQL queries. There are two tables and we call them employee and status.
I need to filter duplicate records based on the key and status.
Key : |emplyee_dep_id|employee_reg_date|employee_rep_manager|
It is a composite key.
And there is a column in the Employee table called emp_status_id. In the Status table, there are two columns status_code and status_id.
Finally, I need to filter duplicate records based on the composite key with status "promoted" joining two tables.
I have written two queries but need to develop a single query. Could you help me to combine these two queries, please?
Sample data
|emplyee_dep_id|employee_reg_date|employee_rep_manager|status_id|email|
| 1 | 20-01-01 | Anne | 3 |a#a.com|
| 1 | 20-01-01 | Anne | 3 |u#a.com|
| 1 | 20-01-01 | Anne | 3 |y#a.com|
| 1 | 20-01-01 | Anne | 3 |h#a.com|
| 1 | 20-01-01 | Anne | 1 |b#a.com|
|Status_id|status_code|
| 3 | Promoted |
| 1 | Probation |
Query:
SELECT
emp.emplyee_dep_id, emp.employee_reg_date,
emp.employee_rep_manager, employee_status
FROM
employee emp
INNER JOIN
(SELECT
emplyee_dep_id, employee_reg_date, employee_rep_manager,
COUNT(*) AS CountOf
FROM
employee
GROUP BY
emplyee_dep_id, employee_reg_date, employee_rep_manager
HAVING
COUNT(*) > 1) emp1 ON emp.emplyee_dep_id = emp1.emplyee_dep_id
AND emp.employee_reg_date = emp1.employee_reg_date
AND emp.employee_rep_manager = emp1.employee_rep_manager
SELECT
employee_status
FROM
Employee
INNER JOIN
Status ON Employee.status_id = Status.status_id
WHERE
Status.status_code = 'promoted'
Instead of the Employee in the 2nd query, put the 1st query and join with status
SELECT e.*, s.status_code
from
(
SELECT emp.emplyee_dep_id,emp.employee_reg_date,emp.employee_rep_manager,employee_status as status_id
FROM employee emp
INNER JOIN (SELECT
emplyee_dep_id,employee_reg_date,employee_rep_manager, COUNT(*) AS CountOf
FROM employee
GROUP BY emplyee_dep_id,employee_reg_date,employee_rep_manager
HAVING COUNT(*)>1
) emp1
ON emp.emplyee_dep_id=emp1.emplyee_dep_id
AND emp.employee_reg_date=emp1.employee_reg_date
AND emp.employee_rep_manager = emp1.employee_rep_manager
) E
INNER JOIN Staus s
ON E.status_id = s.status_id
where s.status_code = 'promoted'
Group by emplyee_dep_id,employee_reg_date,employee_rep_manager;
And here is the fiddle
I have a table named 'products' and another table named 'rates' that has one to many relation with 'products' table. For each product i have two rows in 'rates' table that i want update one boolean column named 'index' to 1 for each 'product' in 'rates' table.
i used this query :
UPDATE ( SELECT
products.id AS productId,
products.name ,
X.`index` AS `index`,
x.id AS rateId,
x.price, x.discount
FROM products JOIN ( SELECT rates.*
FROM rates
) AS x
WHERE products.id = x.product_id
GROUP BY products.id
) AS y
SET y.index = 1
but id got this error massage:
SQL Error (1288) the target table y of the update is not updatable
i'm new in mysql and i don't know where is my mistake.Thank you for helping
Products Table
| id | name
| 1 | chair
| 2 | bench
Rates Table
| id | product_id | index | value
| 1 | 1 | 0 | xx ==> index = 1
| 2 | 1 | 0 | yy
| 3 | 2 | 0 | zz ==> index = 1
| 4 | 2 | 0 | tt
i want update index column for each product in rates to 1
It looks like you want to update the "first" row in rates for each product_id. If so, you can self-join the table with an aggregate query that computes the minimum id per product_id:
update rates r
inner join (select product_id, min(id) id from rates group by product_id) r1
on r1.id = r.id
set r.index = 1
Trying to formulate my question as good as I can...
I have a pricing table with historic data in it. So per item there is a price for certain dates. The difficulty is that the rows also have a type (1 = price for purchase order, 2 = sales order) and a VendorID.
That VendorID can be filled on a row: the price on that row is then for that specific vendor. If there is no row for a certain item in this table that has a VendorID, but it does have a row where VendorID is null, that row should be in the result.
So, if there are two rows in the result, one with a VendorID value and one with the VendorID being null, the row with the value should be in the result set and the row with the null value may not be in the result set.
Also, the result set should only contain the prices that are the newest, so i have to take in account the 'FromDate'.
The name of the column 'VendorID' is not well chosen because the rows with type = 2 are for sales orders, but let's forget about that for now ;-)
If I want all items for type = 1, would like to have the following result set:
ID | ItemID | FromDate | Type | VendorID | price
------------------------------------------------
1 | 1. | 2020-01-01 | 1 | 97 | 2.45
9 | 2 | 2020-02-15 | 1 | 97 | 3.88
7 | 3 | 2020-01-01 | 1 | 97 | 2.55
Suppose IDs 3,4 and 9 wheren't in the table (so, no pricing for item 2 for specific VendorID 97), the result should be:
ID | ItemID | FromDate | Type | VendorID | price
------------------------------------------------
1 | 1 | 2020-01-01 | 1 | 97 | 2.45
13 | 2 | 2020-01-01 | 1 | NULL | 999.45
7 | 3 | 2020-01-01 | 1 | 97 | 2.55
For ItemID 2 this would mean that there isn't a specific price set for VendorID 97 but there is a general price set (VendorID is null) and this price should now be placed in the result set.
I hope I explained it more clearly now....
I've written loads of queries now and also googled a lot but I cannot find how to make it do what I want. I tried distinct, sorting, but no luck. Must be something simple but I can't find it.
Up until now I have the following Mysql query but a) it outputs both the rows where VendorID is null and where it has value and b) I think its very overcomplicated but can't figure out how to make it simpler and faster.
SELECT I.ItemID, I.Name, b.vendorID, b.max_date, IP.Price, T.Percentage
FROM Items I
JOIN ( SELECT ItemID, VendorID, MAX(FromDate) max_date, type
FROM ItemPrices
WHERE Type = 1 AND FromDate < '2020-02-30'
AND VendorID = (SELECT ID
FROM Vendors
WHERE VendorID = 'V001')
OR VendorID IS NULL
GROUP BY ItemID, VendorID
) b ON I.ID = b.ItemID
JOIN ItemPrices IP ON IP.ItemID = b.ItemID
AND IP.Type = b.type
AND IP.FromDate = b.max_date
AND (IP.VendorID = b.VendorID OR IP.VendorID IS NULL)
LEFT JOIN TaxCodes T ON T.ID =
( SELECT TC.TaxCodeID
FROM TaxCombinations TC
WHERE TC.Direction = 1
AND TC.TaxAreaID = (SELECT TaxArea
FROM Vendors
WHERE ID = (SELECT ID
FROM Vendors
WHERE VendorID = 'V001') )
AND TC.ItemTaxID = I.ItemTaxID )
ORDER BY I.ItemID ASC
Also looked at the following urls but still don't know what to do:
Distinct rows with non-null values taking precedence over nulls
Select the non-null value if exists else null, but always select the row
Can someone please help me?
If you want to get the newest for each ItemID corresponding to the Type selection, you can make a sub-query to return the newest price first then join the original table to show it in the end output. Below are the example query:
SELECT A.*
FROM ItemPrices A
JOIN ( SELECT itemid,
TYPE,
MAX(fromdate) AS mdt
FROM ItemPrices
GROUP BY itemid,TYPE ) B
ON A.itemid=B.itemid
AND A.type=B.type
AND A.fromdate=B.mdt
WHERE A.type=1
ORDER BY A.itemid;
You can view the demo here : https://www.db-fiddle.com/f/7YCaiLYz9DE11wnijWEdi/3
Trying to formulate my question as good as I can...
I have a pricing table with historic data in it. So per item there is a price for certain dates. The difficulty is that the rows also have a type (1 = price for purchase order, 2 = sales order) and a VendorID.
That VendorID can be filled on a row: the price on that row is then for that specific vendor. If there is no row for a certain item in this table that has a VendorID, but it does have a row where VendorID is null, that row should be in the result.
So, if there are two rows in the result, one with a VendorID value and one with the VendorID being null, the row with the value should be in the result set and the row with the null value may not be in the result set.
Also, the result set should only contain the prices that are the newest, so i have to take in account the 'FromDate'.
The name of the column 'VendorID' is not well chosen because the rows with type = 2 are for sales orders, but let's forget about that for now ;-)
If I want all items for type = 1, would like to have the following result set:
ID | ItemID | FromDate | Type | VendorID | price
------------------------------------------------
1 | 1. | 2020-01-01 | 1 | 97 | 2.45
9 | 2 | 2020-02-15 | 1 | 97 | 3.88
7 | 3 | 2020-01-01 | 1 | 97 | 2.55
Suppose IDs 3,4 and 9 wheren't in the table (so, no pricing for item 2 for specific VendorID 97), the result should be:
ID | ItemID | FromDate | Type | VendorID | price
------------------------------------------------
1 | 1 | 2020-01-01 | 1 | 97 | 2.45
13 | 2 | 2020-01-01 | 1 | NULL | 999.45
7 | 3 | 2020-01-01 | 1 | 97 | 2.55
For ItemID 2 this would mean that there isn't a specific price set for VendorID 97 but there is a general price set (VendorID is null) and this price should now be placed in the result set.
I hope I explained it more clearly now....
I've written loads of queries now and also googled a lot but I cannot find how to make it do what I want. I tried distinct, sorting, but no luck. Must be something simple but I can't find it.
Up until now I have the following Mysql query but a) it outputs both the rows where VendorID is null and where it has value and b) I think its very overcomplicated but can't figure out how to make it simpler and faster.
SELECT I.ItemID, I.Name, b.vendorID, b.max_date, IP.Price, T.Percentage
FROM Items I
JOIN
(
SELECT ItemID, VendorID, MAX(FromDate) max_date, type
FROM ItemPrices
WHERE
Type = 1 AND
FromDate < '2020-02-30' AND
VendorID = (SELECT ID FROM Vendors WHERE VendorID = 'V001') OR VendorID IS NULL
GROUP BY ItemID, VendorID
) b ON I.ID = b.ItemID
JOIN ItemPrices IP ON IP.ItemID = b.ItemID AND IP.Type = b.type AND IP.FromDate = b.max_date AND (IP.VendorID = b.VendorID OR IP.VendorID IS NULL)
LEFT JOIN TaxCodes T ON T.ID =
(
SELECT TC.TaxCodeID FROM TaxCombinations TC
WHERE
TC.Direction = 1 AND
TC.TaxAreaID = (SELECT TaxArea FROM Vendors WHERE ID = (SELECT ID FROM Vendors WHERE VendorID = 'V001') )
AND TC.ItemTaxID = I.ItemTaxID
)
ORDER BY I.ItemID ASC
Also looked at the following urls but still don't know what to do:
Distinct rows with non-null values taking precedence over nulls
Select the non-null value if exists else null, but always select the row
Can someone please help me?
With NOT EXISTS:
select t.* from tablename t
where t.vendorid is not null
or not exists (
select 1 from tablename
where itemid = t.itemid and vendorid is not null
)
See the demo.