How to mapping data with text multi level? - sql

How to write sql statement?
Table_Product
+------------------+
| Product |
+------------------+
| AAA |
| ABB |
| ABC |
| ACC |
+------------------+
Table_Mapping
+---------------+---------------+
| ProductGroup | ProductName |
+---------------+---------------+
| A* | Product1 |
| ABC | Product2 |
+---------------+---------------+
I need the following result:
+------------+---------------+
| Product | ProductName |
+------------+---------------+
| AAA | Product1 |
| ABB | Product1 |
| ABC | Product2 |
| ACC | Product1 |
+------------+---------------+
Thanks,
TOM

The following query does what you describe when run from within the Access application itself:
SELECT Table_Product.Product, Table_Mapping.ProductName
FROM
Table_Product
INNER JOIN
Table_Mapping
ON Table_Product.Product = Table_Mapping.ProductGroup
WHERE InStr(Table_Mapping.ProductGroup, "*") = 0
UNION ALL
SELECT Table_Product.Product, Table_Mapping.ProductName
FROM
Table_Product
INNER JOIN
Table_Mapping
ON Table_Product.Product LIKE Table_Mapping.ProductGroup
WHERE InStr(Table_Mapping.ProductGroup, "*") > 0
AND Table_Product.Product NOT IN (SELECT ProductGroup FROM Table_Mapping)
ORDER BY 1

You would want to use CASE WHEN. Try this:
Select Product, (CASE
WHEN Product = 'AAA' THEN 'Product1'
WHEN Product = 'ABB' THEN 'Product1'
WHEN Product = 'ABC' THEN 'Product2'
WHEN Product = 'ACC' THEN 'Product1'
ELSE Null END) as 'ProductName'
from Table_Product
order by Product

If this is literally how it is uimplemented then you can
Select Product, ProductName
From Table_Product P
inner join Table_Mapping M
On M.Product_Group & '*' like P.Product
You would have to remove change your A* Product record to A Product though. I.e. you can't embed the wildcards in the record. If you want to have wildcards at the start it will run a lot slower.

Related

How can I query this as I want?

I have three table like this:
Product
| ID | Name |
+----------------+
| 1 | Product A |
| 2 | Product B |
ProductDescription
| ID | Description |
+------------------------------------+
| 1 | Product A English Description |
| 2 | Product A Spanish Description |
| 3 | Product B English Description |
| 4 | Product B Spanish Description |
And finally a table to connect 2 above table
ProductProductDescription
| ProductID | ProductDescriptionID |
+----------------------------------+
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 2 | 4 |
When I joined 3 above table normally, I got this
| ProductID | ProductDescripton |
+-------------------------------------------+
| 1 | Product A English Description |
| 1 | Product A Spanish Description |
| 2 | Product B English Description |
| 2 | Product B Spanish Description |
But I want to query into this:
| ProductID | English Description | Spanish Description |
+---------------------------------------------------------------------------+
| 1 | Product A English Description| Product A Spanish Description |
| 2 | Product B English Description| Product B Spanish Description |
Can you help me?
I think you want conditional aggregation:
select ppd.id,
max(case when pd.description like '%English%' then pd.description end) english_description,
max(case when pd.description like '%Spanish%' then pd.description end) spanish_description
from ProductProductDescription ppd
inner join ProductDescription pd on pd.id = ppd.productdescriptionid
group by ppd.id
Notes:
design-wise, it would be far better to have another column in product description table that represents the language of the description, rather than relying on the description itself
you don't need the product table to generate the expected result; but if you do, then just add another join to the query
One option would be using PIVOT Clause (if available for your DBMS) as
SELECT *
FROM
(
SELECT ppd.ProductID, pd.Description, LTRIM(REPLACE(pd.Description,p.Name)) AS Title
FROM ProductDescription pd
JOIN ProductProductDescription ppd
ON ppd.ProductDescriptionID = pd.ID
JOIN Product p
ON ppd.ProductID = p.ID
)
PIVOT
(
MAX(Description) FOR Title IN ('English Description' AS " English Description",
'Spanish Description' AS " Spanish Description")
)
Demo

Replace subqueries in where statement

I've built a query that intends to find products (products table) with both a 'used' offer and a 'new' offer, and get the lowest price for each. A product can have multiple offers (link_prices table). The offer's condition is determined by the name of the merchant (merchants table): a name without used and occasion is a 'new' offer, a name with used is a 'used' offer.
Here's a sample of the tables (PostgreSQL):
merchants
+----+---------------+
| id | name |
+----+---------------+
| 1 | amazon_used |
| 2 | ebay_location |
| 3 | amazon |
| 4 | target |
| 5 | target_used |
+----+---------------+
link_prices
+----+-------------+------------+-------+
| id | merchant_id | product_id | price |
+----+-------------+------------+-------+
| 1 | 1 | 1 | |
| 2 | 1 | 2 | 20 |
| 3 | 4 | 2 | 30 |
| 4 | 5 | 2 | 5 |
| 5 | 2 | 3 | 10 |
| 6 | 1 | 4 | 80 |
| 7 | 1 | 3 | 100 |
+----+-------------+------------+-------+
In this case, I'm expecting my query to return
+------------+----------------+---------------+
| product_id | min_used_price | min_new_price |
+------------+----------------+---------------+
| 2 | 5 | 30 |
+------------+----------------+---------------+
I've got the following query to work but I feel like I shouldn't need to use subqueries to achieve this. I just can't work my head around it. Any help would be appreciated to optimize this query.
SELECT products.id,
MIN(CASE WHEN merchants.name ILIKE '%used%' THEN link_prices.price END) as min_used_price,
MIN(CASE WHEN merchants.name NOT ILIKE '%used%' THEN link_prices.price END) as min_new_price
FROM products
INNER JOIN link_prices ON link_prices.product_id = products.id
INNER JOIN merchants ON merchants.id = link_prices.merchant_id
WHERE
products.id IN (
SELECT products.id
FROM products
INNER JOIN link_prices ON link_prices.product_id = products.id
INNER JOIN merchants ON merchants.id = link_prices.merchant_id
AND merchants.name ILIKE '%used%'
AND link_prices.price IS NOT NULL
AND link_prices.price <> 0
)
AND products.id IN (
SELECT products.id
FROM products
INNER JOIN link_prices ON link_prices.product_id = products.id
INNER JOIN merchants ON merchants.id = link_prices.merchant_id
AND merchants.name NOT ILIKE '%used%'
AND merchants.name NOT ILIKE '%location%'
AND link_prices.price IS NOT NULL
AND link_prices.price <> 0
)
GROUP BY products.id
Thanks a ton!
Your description makes this sound like conditional aggregation:
select lp.product_id,
min(lp.price) filter (where m.name like '%used') as min_used_price,
min(lp.price) filter (where m.name not like '%used') as min_new_price
from merchants m join
link_prices lp
on lp.merchant_id = m.id
group by lp.product_id;
You sample query is much more complicated and has conditions that are not mentioned in the text of the question. But I think this structure will work for what you want to do.

Return 0 quantity when SKU not found

I have in my database 2 tables: warehouse and warehouse_inventory.
My warehouse table looks like:
name | warehouse_id |
--------+----------------|
name_1 | warehouse_id_1 |
name_2 | warehouse_id_2 |
name_3 | warehouse_id_3 |
My warehouse_inventory table looks like:
warehouse_id | SKU | quantity |
----------------+-------------+----------|
warehouse_id_1 | item_sku_1 | 100 |
warehouse_id_2 | item_sku_1 | 100 |
And now, I am looking for a solution which gets me result like this:
name | warehouse_id | SKU | quantity |
--------+-----------------------------+----------|
name_1 | warehouse_id_1 | item_sku_1 | 100 |
name_1 | warehouse_id_1 | item_sku_2 | 0 |
name_2 | warehouse_id_2 | item_sku_1 | 100 |
name_2 | warehouse_id_2 | item_sku_2 | 0 |
name_3 | warehouse_id_3 | item_sku_1 | 0 |
name_3 | warehouse_id_3 | item_sku_2 | 0 |
when I select with where condition in SQL query:
SELECT * FROM [what's here?] WHERE warehouse_inventory.SKU IN ('item_sku_1', 'item_sku_2')
You can't do this if you don't have a table with all the SKU you have on your database.
So, assuming that you have a table called [item] for all your item master data, you should do that:
SELECT W0.name, W0.warehouse_id, I0.SKU, ISNULL(W1.quatity, 0) as 'Quantity'
FROM [item] I0
CROSS JOIN [warehouse] W0
LEFT JOIN [warehouse_inventory] W1 ON W1.warehouse_id = W0.warehouse_id AND W1.SKU = I0.SKU
On SAP Business One we do this:
SELECT W0.WhsName, W0.WhsCode, I0.ItemCode, ISNULL(W1.OnHand, 0) as 'Quantity'
FROM OITM I0
CROSS JOIN OWHS W0
LEFT JOIN OITW W1 ON W1.WhsCode = W0.WhsCode AND W1.ItemCode = I0.ItemCode
ORDER BY 1 DESC
You can use CROSS JOIN with LEFT JOIN:
select w.name, w.warehouse_id, wii.SKU, coalesce(i.quantity, 0) as quantity
from warehouse w cross join
warehouse_inventory wii left join
warehouse_inventory i
on i.warehouse_id = w.warehouse_id and i.SKU = wii.SKU
order by w.name;

how to bake in a record count in a sql query

I have a query that looks like this:
select id, extension, count(distinct(id)) from publicids group by id,extension;
This is what the results looks like:
id | extension | count
-------------+-------------------------+-------
18459154909 | 12333 | 1
18459154909 | 9891114 | 1
18459154919 | 43244 | 1
18459154919 | 8776232 | 1
18766145025 | 12311 | 1
18766145025 | 1122111 | 1
18766145201 | 12422 | 1
18766145201 | 14141 | 1
But what I really want is for the results to look like this:
id | extension | count
-------------+-------------------------+-------
18459154909 | 12333 | 2
18459154909 | 9891114 | 2
18459154919 | 43244 | 2
18459154919 | 8776232 | 2
18766145025 | 12311 | 2
18766145025 | 1122111 | 2
18766145201 | 12422 | 2
18766145201 | 14141 | 2
I'm trying to get the count field to show the total number of records that have the same id.
Any suggestions would be appreciated
I think you want to count distincts extentions, not ids.
Run this query:
select id
, extension
(select count(*) from publicids p1 where p.id = p1.id ) distinct_id_count
from publicids p
group by id,extension;
This is more or less the same as Pastor's answer. Depending on what the optimizer does it might be faster with higher record count source tables.
select p.id, p.extension, p2.id_count
from publicids p
inner join (
select id, count(*) as id_count
from publicids group by id
) as p2 on p.id = p2.id

Get distinct of minimum value

I have this table test in Hive.
+----------+-------+-------+
| name | price | notes |
+----------+-------+-------+
| product1 | 100 | |
| product1 | 200 | note1 |
| product2 | 10 | note2 |
| product2 | 5 | note2 |
+----------+-------+-------+
and I expect to get this result (distinct of products with minimum price)
+----------+-------+-------+
| name | price | notes |
+----------+-------+-------+
| product1 | 100 | |
| product2 | 5 | note2 |
+----------+-------+-------+
I can't use the following query because of different notes in product1.
SELECT name, MIN(price), notes
FROM test
GROUP BY name, notes;
+----------+-------+-------+
| name | price | notes |
+----------+-------+-------+
| product1 | 100 | |
| product1 | 200 | note1 |
| product2 | 5 | note2 |
+----------+-------+-------+
Remove notes in group by and try again:-
SELECT name, MIN(price), notes
FROM test
GROUP BY name
Run Code
Try this
SELECT name,
SUBSTRING_INDEX(GROUP_CONCAT(price ORDER BY price DESC),',',1) AS min_price,
SUBSTRING_INDEX(GROUP_CONCAT(notes ORDER BY price DESC),',',1) AS note_value
FROM test
GROUP BY name;
You can do this in Hive with windowing functions.
Query:
select distinct name
, min_price
, notes
from (
select *
, min(price) over (partition by name) num_price
from db.table ) x
where min_price = price
Output:
product1 100
product2 5 note2
This can be found using a subquery as well.
hive> select A.name,A.price,B.notes from (select name,min(price) as price from products group by name) as A
inner join (select name,price,notes from products) as B
on a.name = b.name and a.price = b.price;
The above query will give the output as:
product1 100
product2 5 note2
But, the suquery approach has 2 iterations over the same table and is not suggested for larger tables.
For larger tables,see #GoBrewers14 answer:
hive> select name,price,notes from (select *, min(price)over(partition by name) as min_price from products) as a
> where a.price = a.min_price;