I have an part inventory table that stores parts by PartName, WarehouseId, VendorCode (main interest columns). It should only have unique PartName entries by WarehouseId and VendorCode. However, entries are mixed, and I need to get the PartName, WarehouseId and Vendor for such a case. E.g:
ABC133, Warehouse 10, VendorCode 1234
ABC133, Warehouse 10, VendorCode 1222
BBB111, Warehouse 20, VendorCode 1111
BBB111, Warehouse 20, VendorCode 2222
I have customized a query found on this site to do this, but it only brings the first "duplicate" for every duplicate PartName, and I need to get all the faulty entries:
ABC133, Warehouse 10, VendorCode 1222
BBB111, Warehouse 20, VendorCode 1111
This is the query I use:
SELECT i.MFGPN, i.VendorCode, i.WarehouseID FROM edi_846_inventory i
INNER JOIN (SELECT MFGPN FROM edi_846_inventory
GROUP BY MFGPN HAVING count(MFGPN) > 1 and count(VendorCode) > 1) dup ON i.MFGPN = dup.MFGPN
where MFGPN is the PartName
Thanks
This is the query that you want:
SELECT i.MFGPN, i.VendorCode, i.WarehouseID
FROM edi_846_inventory i INNER JOIN
(SELECT MFGPN, WarehouseID
FROM edi_846_inventory
GROUP BY MFGPN, WarehouseID
HAVING count(*) > 1
) dup
ON i.MFGPN = dup.MFGPN AND i.WarehouseID = dup.WarehouseID;
In other words, your subquery needs to aggregate by both MFGPN and WarehouseID.
Also, just concatenating the vendors together might be sufficient for you:
SELECT MFGPN, WarehouseID, GROUP_CONCAT(VendorCode) as Vendors
FROM edi_846_inventory
GROUP BY MFGPN, WarehouseID
HAVING count(*) > 1
A work colleague found a solution:
select i.MFGPN, i.WarehouseID, i.VendorCode, i.IngramSKU
from edi_846_inventory i
where i.MFGPN in
(
select *
from
(
select distinct i.MFGPN
from edi_846_inventory i
group by i.MFGPN, i.WarehouseID
having count(*) > 1
) dup
)
order by i.MFGPN, i.WarehouseID
Related
I have two suppliers where I am trying to filter the products to achieve the following:
Select Products from Table1(supplier 1) that are not already present in Table3 and some further filtering on categories (Working)
Select Products from Table2 (Supplier 2) that are not already present in Table3 (Working)
There are duplicate products from Table1 and Table2. I want to filter these so the resulting table does not have duplicate products but I want to do this by selecting the cheaper supplier rate as the product that ends up in the table. (Stuck on this).
My current SQL query at the moment is the below which does the first two items but I am unsure how to modify to get the third item above working. Any suggestions greatly appreciated.
SELECT Vendor,
VendorStockCode AS SKU,
StockDescription AS Description,
StockAvailable AS Stock
FROM Table1
WHERE NOT EXISTS (SELECT sku
FROM Table3_product_meta_lookup
WHERE Table1.VendorStockCode = Table3_product_meta_lookup.sku)
AND PrimaryCategory != 'SERVICES'
AND PrimaryCategory != 'WARRANTY'
AND cast(DealerEx as decimal(10,2)) <= cast('15000.00' as decimal(10,2))
UNION
SELECT Manufacture_Name,
Manufacture_Code,
Short_Description,
Stock_Qty
FROM Table2
WHERE NOT EXISTS (SELECT sku
FROM Table3_product_meta_lookup
WHERE Manufacture_Code = Table3_product_meta_lookup.sku)
OK, after some experiment, I followed a similar line to what I had and seems to be working. Not sure if it is the most efficient manner but is getting the data I am after. Thank you for those who responded. I have pasted the final query below for reference:
SELECT Vendor, VendorStockCode AS SKU,
StockDescription AS Description,
StockAvailable AS Stock
FROM Table1
WHERE NOT EXISTS (
SELECT sku
FROM Table3_product_meta_lookup
WHERE Table1.VendorStockCode = Table3_product_meta_lookup.sku )
AND PrimaryCategory != 'SERVICES'
AND PrimaryCategory != 'WARRANTY'
AND CAST(DealerEx AS DECIMAL(10,2)) <= CAST('15000.00' AS DECIMAL(10,2))
AND NOT EXISTS (
SELECT Manufacture_Code
FROM Table2
WHERE VendorStockCode = Manufacture_Code
AND CAST(DealerEx AS DECIMAL(10,2)) >= CAST(ExTax AS DECIMAL(10,2)))
UNION
SELECT Manufacture_Name, Manufacture_Code, Short_Description,
Stock_Qty
FROM Table2
WHERE NOT EXISTS (
SELECT sku
FROM Table3_product_meta_lookup
WHERE Manufacture_Code = Table3_product_meta_lookup.sku )
AND NOT EXISTS (
SELECT VendorStockCode
FROM Table1
WHERE VendorStockCode = Manufacture_Code
AND CAST(DealerEx AS DECIMAL(10,2)) < CAST(ExTax AS DECIMAL(10,2)));
How to calculate supplier rate?
You want to remove the duplicate products and leave one which is lower in supplier rate?
Assuming that you've already collected all data from table1 and table2 with supplier_rate column and union them into a table 'table_a'.
It will be easier to filter the duplicated SKUs with different suppliers and leave on with one supplier with a lower rate.
The tested query below.
select vendor,sku,stock from (
select vendor,sku,stock,supplier_rate,rank() over(PARTITION by sku order by supplier_rate) as rk from table_a) pd
where rk = 1;
The input table data:
vendorname sku stock supplier_rate
vendor1 100 1000 30
Manufacture1 100 2000 40
vendor3 200 1500 50
Manufacture2 300 2000 60
Manufacture3 200 1200 25
The output table data:
vendorname sku stock
vendor1 100 1000
Manufacture3 200 1200
Manufacture2 300 2000
I have a database table "tblfavs" with five columns: id, userid, logoid, favdate, did.
I want to determine the percentage of a user's (userid) favorites (id) that share the same designer id (did), and where userid <> did, displayed from highest percentage to lowest.
In pseudo-query format:
SELECT [percentage], userid, did
FROM tblfavs
WHERE record has the same userid and did
AND userid <> did
GROUP BY userid
ORDER BY [percentage] DESC
I can't get my head around the query to accomplish this. Help appreciated!
Edit:
Sample data
1, 1, 5, 2017-01-01, 2
2, 7, 3, 2017-01-02, 5
3, 1, 8, 2017-01-02, 2
4, 7, 1, 2017-01-02, 3
In this set user 1 (second column) has two entries and both have "2" as the designer id (final column).
Expected output
100%, userid 1, did 2
50%, userid 7, did 5
50%, userid 7, did 3
etc.
This is easier in other DBMS which feature window functions (e.g. COUNT OVER). However, this is not that difficult in MySQL either. You just need two aggregations: Count per userid and did, count per userid, divide.
select
ud.cnt * 100.0 / u.cnt as percentage,
ud.userid,
ud.did
from
(
select userid, did, count(*) as cnt
from tblfavs
group by userid, did
) ud
join
(
select userid, count(*) as cnt
from tblfavs
group by userid
) u on u.userid = ud.userid
order by percentage desc;
Try this (improved from the previous answer to match your exact input-so you get % for each row not agregated)
select
ud.cnt2 * 100.0 / u.cnt as percentage,
ud.userid,
ud.did
from
(
select
out3.userid,out3.did, cnt2
from
(select userid,did from tblfavs) out3
join
(
select
userid, did, count(*) as cnt2
from tblfavs
group by userid, did
) ud on ud.userid = out3.userid and ud.did = out3.did
) ud
join
(
select userid, count(*) as cnt
from tblfavs
group by userid
) u on u.userid = ud.userid
order by percentage desc;
I have the following data inside a table:
id person_id item_id price
1 1 1 10
2 1 1 20
3 1 3 50
Now what I want to do is group by the item ID, select the id that has the highest value and take the price.
E.g. the sum would be: (20 + 50) and ignore the 10.
I am using the following:
SELECT SUM(`price`)
FROM
(SELECT id, person_id, item_id, price
FROM `table` tbl
INNER JOIN person p USING (person_id)
WHERE p.person_id = 1
ORDER BY id DESC) x
GROUP BY item_id
However, this query is still adding (10 + 20 + 50), which is obviously not what I need to have.
Any ideas to where I am going wrong?
Here is what you are trying to achieve. First you need grouping in a subquery and not in outer query. In outer query you need only sum:
SELECT SUM(`price`)
FROM
(SELECT MAX(price) as price
FROM `table` tbl
INNER JOIN person p USING (person_id)
WHERE p.person_id = 1
GROUP BY item_id) x
http://sqlfiddle.com/#!9/40803/5
SELECT SUM(t1.price)
FROM tbl t1
LEFT JOIN tbl t2
ON t1.person_id= t2.person_id
AND t1.item_id = t2.item_id
AND t1.id<t2.id
WHERE t1.person_id = 1
AND t2.id IS NULL;
I'm not sure if this is the only requirement you have. If so, try this.
SELECT SUM(price)
FROM
(SELECT MAX(price)
FROM table
WHERE person_id = 1
GROUP BY item_id)
First of all - you don't need the person table, because the other table already contains the person_id. So i removed it from the examples.
Your query returns a sum of prices for each item.
If you replace SELECT SUM(price) with SELECT item_id, SUM(price) you wil get
item_id SUM(`price`)
1 30
3 50
But that is not what you want. Neither is it what you wrote in the question " (10 + 20 + 50)".
Now replacing the first line with SELECT id, item_id, SUM(price) you will get one row for each item with the highest id.
id item_id price
2 1 20
3 3 50
This works because of the "undocumented feature" of MySQL, wich allows you to select columns that are not listed in the GROUP BY clause and get the first row from the subselect each group (each item in this case).
Now you only need to sum the price column in an additional outer select
SELECT SUM(price)
FROM (
SELECT id, item_id ,price
FROM (
SELECT id, person_id, item_id, price
FROM `table` tbl
WHERE tbl.person_id = 1
ORDER BY id DESC ) x
GROUP BY item_id
) y
However i do not recomend to use that "feature". While it still works on MySQL 5.6, you never know if that will work with newer versions. It already doesn't work on MariaDB.
Instead you can determite the MAX(id) for each item in an subselect, select only the rows with the determined ids and get the summed price of them.
SELECT SUM(`price`)
FROM `table` tbl
WHERE tbl.id IN (
SELECT MAX(tbl2.id)
FROM `table` tbl2
WHERE tbl2.person_id = 1
GROUP BY tbl2.item_id
)
Another solution (wich internaly does the same) is
SELECT SUM(`price`)
FROM `table` tbl
JOIN (
SELECT MAX(tbl2.id) as id
FROM `table` tbl2
WHERE tbl2.person_id = 1
GROUP BY tbl2.item_id
) x ON x.id = tbl.id
Alex's solution also works fine, if the groups (number of rows per person and item) are rather small.
You have used group by in main query, but it is on subquery like
SELECT id, person_id, item_id, SUM(`price`) FROM ( SELECT MAX(price) FROM `table` tbl WHERE p.person_id = 1 GROUP BY item_id ) AS x
I am having a table with following schema:
CUSTOMERS (id INT, name VARCHAR(10), height VARCHAR(10), weight INT)
id is the primary key. I want to find out rows in which people who are having exactly same name, same height and same weight. In other words, I want to find out duplicates with-respect-to name, height and weight.
Example table:
1, sam, 160, 100
2, ron, 167, 88
3, john, 150, 90
4, sam, 160, 100
5, rick, 158, 110
6, john, 150, 90
7, sam, 166, 110
Example Output:
Now since there are people with same name, same height and same weight:
sam (id=1), sam (id=4)
and
john (id=3), john (id=6)
I want to get these ids. It is also okay if I get only one id per match (i.e. id=1 from first match and id=3 from second match).
I am trying this query but not sure if it is correct or not.
SELECT id
FROM customers
GROUP BY name, height, weight
Try this (valid for sql server):
SELECT
t.NAME,
'Ids = '+
(
SELECT cast(Id as varchar)+','
FROM Customers c
WHERE c.NAME = t.NAME AND c.Weight = t.Weight AND c.Height = t.Height
FOR XML PATH('')
)
FROM
(
SELECT Name, height, weight
FROM Customers
GROUP BY Name, height, weight
HAVING COUNT(*) > 1
) t
OR
as you asked - only one Id per match
SELECT
t.NAME,
c.Id
FROM
(
SELECT Name, height, weight
FROM Customers
GROUP BY Name, height, weight
HAVING COUNT(*) > 1
) t
JOIN Customers c ON t.NAME AND c.Weight = t.Weight AND c.Height = t.Height
SELECT *
FROM customers C
INNER JOIN
(
SELECT name, height, weight
FROM customers
GROUP BY name, height, weight
HAVING COUNT(*) > 1
) X ON C.name = X.name AND C.height = X.height AND C.weight = X.weight
SELECT c.*
FROM customers c
JOIN (
SELECT name, height, weight
FROM
GROUP BY name, height, weight
HAVING count(*) > 1
) t ON c.name = t.name and c.height = t.height and c.weight = t.weight
you are on the right way:
SELECT min(id)
FROM customers
GROUP BY name, height, weight
HAVING COUNT(*) > 1
I don't know what you are using since you tagged several databases.
In Sql server you won't be able to select the id without putting it in the SELECT.
so if you want to select other fields besides the ones in the group clasue you can use PARTITION BY. Something like this:
SELECT id,
ROW_NUMBER() OVER(PARTITION BY c.name, c.height, c.weight ORDER BY c.name) AS DuplicateCount
FROM customers c
This will give you the ids of the duplicates that you have with the same name, height and weight.
I'm not sure that this is faster that the other solutions though, but, you can profile it and compare.
If it is okay to get only one id per match as you say, you are close to solution:
SELECT
min( id )
,name, height, weight --<-- oncly if you need/want
FROM customers
GROUP BY name, height, weight
HAVING count(*) > 1
Ok, I have a query over two tables. I need to get two sums. I do a group by so the sum() works correctly.
SELECT sum(a.x), sum(b.y) FROM a,b GROUP BY a.n where a.n=b.m
So far this works well, but the problem is i need to group them differently for the second sum (sum(b.y)), than for the first sum (sum(a.x)).
The real query is somewhat more complex but this is my main problem.
This is what i actually try to select sum(stock.amount) - if( sold.amount IS NULL , 0, sum( sold.amount ) )
How can I solve that in one query?
since you are not writing down the tables I am gonna make a wild guess and assume the tables are like :
stock : id, item_id, amount
sold : id, item_id, amount
then again I assume that you need the stock_in_total, sold_total, left_total counts
SELECT
stock_sums.item_id,
stock_sums.st_sum as stock_in_total,
COALESCE(sold_sums.so_sum,0) as sold_total,
(stock_sums.st_sum - COALESCE(sold_sums.so_sum,0)) as left_total
FROM (
SELECT stock.item_id as item_id, SUM(stock.amount) as st_sum
FROM stock
GROUP BY item_id
) as stock_sums
LEFT JOIN (
SELECT sold.item_id as item_id, SUM(sold.amount) as so_sum
FROM sold
GROUP by item_id
) as sold_sums ON stock_sums.item_id = sold_sums.item_id
I hope this would help.
Here is how I would do it. I assume that Stock is the main table, with an ID and an amount, and that Sold maps to Stock via an ID value, and has zero to many records for each Stock item.
SELECT Q1.id, Q1.Total1, Q2.Total2
, Q1.Total1 - COALESCE(Q2.Total2,0) as Outstanding
FROM (
SELECT id, SUM(amount) as Total1
FROM Stock GROUP BY id
) as Q1
LEFT OUTER JOIN (
SELECT id, SUM(Amount) as Total2
FROM Sold GROUP BY id
) as Q2
ON Q2.id = Q1.id
Note that simply formatting your SQL into a clean way forces you to break it into logical parts and will often reveal exactly what is wrong with the query.
The example above also handles correctly the cases where there is not match in the Sold table.
Cheers,
Daniel
(Code Assumptions)
DROP TABLE Stock
CREATE TABLE Stock (
id integer
, amount decimal(10,2)
)
INSERT INTO Stock (id, amount ) VALUES ( 1, 10.1);
INSERT INTO Stock (id, amount ) VALUES ( 2, 20.2);
INSERT INTO Stock (id, amount ) VALUES ( 3, 30.3);
SELECT * FROM STOCK
DROP TABLE Sold
CREATE TABLE Sold (
id integer
, amount decimal(10,2)
)
INSERT INTO Sold (id, amount ) VALUES ( 1, 1.1);
INSERT INTO Sold (id, amount ) VALUES ( 1, 2.2);
INSERT INTO Sold (id, amount ) VALUES ( 1, 3.3);
INSERT INTO Sold (id, amount ) VALUES ( 2, 2.22);
SELECT * FROM Sold
SELECT Q1.id, Q1.Total1, Q2.Total2
, Q1.Total1 - COALESCE(Q2.Total2,0) as Outstanding
FROM (
SELECT id, SUM(amount) as Total1
FROM Stock GROUP BY id
) as Q1
LEFT OUTER JOIN (
SELECT id, SUM(Amount) as Total2
FROM Sold GROUP BY id
) as Q2
ON Q2.id = Q1.id
Results:
id Total1 Total2 Outstanding
1 10.10 6.60 3.50
2 20.20 2.22 17.98
3 30.30 30.30
REVISION
It sounds like you want the total amount of stock you have as one count for each different stock. Then you want how much stock you have left for each stock based on what has been sold. Correct?
If so check this out:
select stock, sum(a.x) as sharesBeforeSale, (sum(a.x) - sum(b.y)) as sharesAfterSale
FROM db.table1 a, db.table2 b
WHERE a.UNIQUEID = b.UNIQUEID AND b.y IS NOT NULL
GROUP BY a.UNIQUEID;
Does that accomplish what you are looking to do?
stock sharesBeforeSale sharesAfterSale
duk 100 25
orc 101 101
yrc 54 41
Enjoy!
Sample tables
db.table1 (stock owned):
UNIQUEID x stock
1 100 duk
2 101 orc
3 54 yrc
db.table2 (stock sold):
UNIQUEID y
1 75
2 0
3 13