SQL to generate report of entity-attribute-value structured data - sql

I have 3 tables:
Productmaster:
ProductId PName PDescription
Attributes:
AttributeID attName
---- ----
1 Brand
2 Category
3 Artist
ProductAttributeValues
paId ProductId AttributeID AttributeValues
A product can have multiple attributes.
Here's the desired output:
ProductId ProductDesc Brand Category Artist
--- --- --- --- ---
1 sadasd Brand1 Category1 Artist1
2 sadasds Brand2 Category3 Artist4
How can I get this output?
Thanks in advance.

You should left join for each attribute value you want to pull in, e.g.
select p.ProductId,p.ProductDesc,
a1.AttributeValues as Brand,
a2.AttributeValues as Category,
a3.AttributeValues as Artist,
from Product p
left join ProductAttributeValues a1 on(p.ProductId=a1.ProductId and a1.AttributeID=1)
left join ProductAttributeValues a2 on(p.ProductId=a2.ProductId and a2.AttributeID=2)
left join ProductAttributeValues a3 on(p.ProductId=a3.ProductId and a3.AttributeID=3)
To turn this back into English, "give me all products, and for each one, give me a brand, category and artist attribute if they exist"
I've assumed that a product has only one or zero values for each attribute.

Assumed that every attribute appears exactly once per product:
SELECT
pm.ProductId as ProductId,
pm.PDescription as ProductDesc,
pav_Brand.AttributeValues as Brand,
pav_Category.AttributeValues as Category,
pav_Artist.AttributeValues as Artist
FROM
ProductMaster pm
inner join ProductAttributeValues pav_Brand
on pm.productId == pav_Brand.ProductId
inner join Attributes a_Brand
on pav_Brand.AttributeId = a_Brand.AttributeId
AND a_Brand.attName = 'Brand'
inner join ProductAttributeValues pav_Category
on pm.productId == pav_Category.ProductId
inner join Attributes a_Category
on pav_Category.AttributeId = a_Category.AttributeId
AND a_Brand.attName = 'Category'
inner join ProductAttributeValues pav_Artist
on pm.productId == pav_Artist.ProductId
inner join Attributes a_Artist
on pav_Category.AttributeId = a_Artist.AttributeId
AND a_Brand.attName = 'Artist'
You can use left outer joins if the data is not always available.

SELECT ProductId, ProductDesc,
(
SELECT AttributeValues
FROM ProductAttributeValues pv
WHERE pv.AttributeID = 1
AND pv.ProductID = p.ProductID
) AS Brand,
(
SELECT AttributeValues
FROM ProductAttributeValues pv
WHERE pv.AttributeID = 2
AND pv.ProductID = p.ProductID
) AS Category,
(
SELECT AttributeValues
FROM ProductAttributeValues pv
WHERE pv.AttributeID = 3
AND pv.ProductID = p.ProductID
) AS Artist
FROM Products p

Try this query, maybe some tweak required
Select pm.ProductId, pm.PDescription, pav1.AttributeValues, pav2.AttributeValues, pav3.AttributeValues
from Productmaster pm, ProductAttributeValues pav1, ProductAttributeValues pav2, ProductAttributeValues pav3
where pm.ProductId = pav1.ProductId
and pav1.AttributeID = 1
and pm.ProductId = pav2.ProductId
and pav2.AttributeID = 2
and pm.ProductId = pav3.ProductId
and pav3.AttributeID = 3

Related

How to get two different value for same reference id in same row

I have two table:
1) Product
2) Item
Product table:
PId Name value1 value2
1 abc 1233 4567
2 xyz 9099 9099
Item Table:
itemId itemname item_start item_end
1 idc 1 2
item_start & item_end are the reference of product table on column PId.
Now when i write below query:
select * from item left join product on item_start = PId and item_end = PId
then it gives only value1 data but i want data like :
itemId itemname item_start item_start_value1 item_start_value2 item_end item_end_value1 item_end_value2
1 idc 1 1233 4567 2 9099 9099
How can i get the above output?
Join the product table twice.
SELECT item.*
, productStart.Value1 AS product_start_value1
, productStart.Value2 AS product_start_value2
, productEnd.Value1 AS product_end_value1
, productEnd.Value2 AS product_end_value2
FROM item
LEFT OUTER
JOIN product productStart
ON productStart.PId = item.item_start
LEFT OUTER
JOIN product productEnd
ON productEnd.PId = item.item_end
As you have 2 FKs on item table, you'd need 2 joins on product table.
SELECT I.itemId, I.itemname, I.item_start, P1.value1 as item_start_value1, P1.value2 as item_start_value2, I.item_end, P2.value1 as item_end_value1, P2.value2 as item_end_value2
FROM item
LEFT JOIN product P1 ON item_start = PId
LEFT JOIN product P2 ON item_end = PId
Example of what can be done:
select * from #Item i inner join #Product p on i.item_Start = p.Pid
inner join #Product p2 on i.Item_end = p2.PId
SELECT item.itemId
, item.itemname
, item.item_start
, productStart.Value1 AS item_start_value1
, productStart.Value2 AS item_start_value2
, item.item_end
, productEnd.Value1 AS item_end_value1
, productEnd.Value2 AS item_end_value2
FROM item
Inner JOIN product productStart ON productStart.PId = item.item_start
Inner JOIN product productEnd ON productEnd.PId = item.item_end

SQL count in select query

I have a sql query that creates a label in a cab file for a shopping company. I want to include the amount of packages in an order, some have multiple.
Each returns line in my select query has an I’d and contains a package but I need to count them.
So I have:
Name Email Weight Price ID
Joe B J#.com 10 12.5. 1
Joe B J#.com 10 12.5. 1
Joe C JC#.com 10 14.5. 2
How can I count the ID’s to return a column called pieces and in this example it would be 2 for ID 1 and 1 for ID 2
Thanks
James
enter code here
Select
'WPX' As 'Product Code',
delivery_header.dh_datetime As 'Shipment Date',
'G' As 'Shipment Type',
order_header_detail.ohd_delivery_email As 'Receiver Email Address',
variant_detail.vad_weight As 'Shipment Weight in KG',
(lots of other fields....)
delivery_header.dh_number As 'Shippers Reference',
(SELECT Count(*)
FROM delivery_header
WHERE
dh_number = OU.dh_number
) As 'Number of Pieces',
From delivery_line_item Inner Join
delivery_header On delivery_header.dh_id = delivery_line_item.dli_dh_id
Inner Join
order_line_item On delivery_line_item.dli_oli_id = order_line_item.oli_id
Inner Join
variant_detail On variant_detail.vad_id = order_line_item.oli_vad_id
Inner Join
order_header On order_header.oh_id = order_line_item.oli_oh_id Inner Join
stock_location On stock_location.sl_id = order_line_item.oli_sl_id Inner Join
customer_detail On customer_detail.cd_id = order_header.oh_cd_id Inner Join
order_header_detail On order_header.oh_id = order_header_detail.ohd_oh_id
Left Join
order_header_analysis On order_header.oh_id = order_header_analysis.oha_oh_id
Left Join
order_customer_analysis On order_header.oh_id =
order_customer_analysis.oca_oh_id Left Join
order_delivery_analysis On order_header.oh_id =
order_delivery_analysis.oda_oh_id Left Join
order_line_analysis On order_line_item.oli_id = order_line_analysis.ola_oli_id
Left Join
order_line_product_analysis On order_line_item.oli_id =
order_line_product_analysis.olpa_oli_id Left Join
order_line_variant_analysis On order_line_item.oli_id =
order_line_variant_analysis.olva_oli_id Inner Join
product_detail On product_detail.pd_id = variant_detail.vad_pd_id Inner Join
delivery_method On delivery_method.dm_id = order_header_detail.ohd_dm_id
Inner Join
delivery_method [Delivery Method] On [Delivery Method].dm_id =
order_header_detail.ohd_dm_id Inner Join
currency On currency.c_id = order_header.oh_c_id And currency.c_id =
delivery_method.dm_c_id And currency.c_id = [Delivery Method].dm_c_id
Where
delivery_header.dh_number IN (199364,199363,199362,199360)
Order By delivery_header.dh_number
You can use GROUP BY with COUNT like this:
SELECT ID, COUNT(*) as count FROM tbl GROUP BY ID
What I understood from your question is that, you are looking for output like
Name Email Weight Price ID Pieces
Joe B J#.com 10 12.5. 1 2
Joe B J#.com 10 12.5. 1 2
Joe C JC#.com 10 14.5. 2 1
Using following query you should get the desired output in most of the DBMS.
SELECT NAME,
EMAIL,
WEIGHT,
PRICE,
ID,
(SELECT Count(*)
FROM <YOUR_TABLE_NAME>
WHERE ID= OU.ID) AS Pieces
FROM <YOUR_TABLE_NAME> OU
Similar Query for MS SQL Server can be
SELECT NAME, EMAIL,WEIGHT , Price, ID,CT.Pieces
FROM <YOUR_TABLE_NAME> OU
CROSS APPLY
(
SELECT COUNT(*) AS Pieces FROM <YOUR_TABLE_NAME> IU WHERE OU.ID=IU.ID
)CT

Avoiding Multiple Joins

I have a table (Manufacturers):
Manufacturer ID
------------------
Lagun 1
Hurco 2
Mazak 3
Haas 4
Then another table (inventory):
Shop Lathe DrillPress CNC Mill ID
-------------------------------------------------
ABC Inc 2 1 3 3 1
VECO 4 2 1 2 2
I need to end up with:
Shop Lathe DrillPress CNC Mill
--------------------------------------------
ABC Inc Hurco Lagun Mazak Mazak
VECO Haas Hurco Lagun Hurco
I have this:
SELECT
Shop, M1.Manufacturer AS Lathe, M2.Manufacturer AS DrillPress,
M3.Manufacturer AS CNC, M4.Manufacturer AS Mill
FROM Inventory I
LEFT JOIN Manufacturers M1 ON M1.ID = I.LstFlowMan
LEFT JOIN Manufacturers M2 ON M2.ID = I.LstFiltFlowMan
LEFT JOIN Manufacturers M3 ON M3.ID = I.LstFilterMan
LEFT JOIN Manufacturers M4 ON M4.ID = I.LstEmitMan
I'm probably missing a better way with a PIVOT or CROSS APPLY or something.
Thanks to #LauDec, here is the SQLServer Version:
select * from (
select SHOP, KEYS, MANUFACTURER from
(select SHOP, LATHE,DRILLPRESS,CNC,MILL from inventory) a
unpivot (val for keys in (LATHE,DRILLPRESS,CNC,MILL)) as unpvt
JOIN Manufacturers M ON M.ID=VAL
) a
PIVOT (
MAX(MANUFACTURER)
FOR keys in (LATHE,DRILLPRESS,CNC,MILL)
) as pp
Here is one way to do it.
SELECT i.shop,
lathe = Max(CASE WHEN i.lathe = m.id THEN m.manufacturer END),
drillpress = Max(CASE WHEN i.drillpress = m.id THEN m.manufacturer END),
mill = Max(CASE WHEN i.mill = m.id THEN m.manufacturer END),
cnc = Max(CASE WHEN i.cnc= m.id THEN m.manufacturer END)
FROM manufacturers m
JOIN inventory i
ON m.id IN ( i.lathe, i.drillpress, i.cnc, i.mill )
GROUP BY i.shop
Consider changing the table structure of inventory table.
inventory : Shop,MachineType,ManufacturerID
Then you can use Pivot/Cross tab to get the result
You can UNPIVOT JOIN and RE-PIVOT
SELECT * FROM (
select SHOP, KEYS, MANUFACTURER from
inventory unpivot ( val for keys in ("LATHE","DRILLPRESS","CNC","MILL"))
JOIN Manufacturers M ON M.ID=VAL
) PIVOT (
MAX(MANUFACTURER)
FOR keys in ('LATHE','DRILLPRESS','CNC','MILL')
)

Sqlite select statement from 2 tables

I have two tables: Products and CategoryProducts.
CategoryProducts contains:
PrdID Category
-----------------
Products contains:
PrdID Barcode Url
-----------------------
I have Product's Barcode value, for example 111111.
Need to select all Products.Url with the same Category, as this item's
Category.
Having Products.PrdID, i can get all needed PrdID's from CategoryProducts like this:
select distinct c1.PrdID
from CategoryProduct_MM c1
where c1.CategoryID in (select c2.CategoryID
from CategoryProduct_MM c2
where c2.PrdID = 175)
Based on your comment, this is what you want:
SELECT t.Url
FROM Products t
INNER JOIN CategoryProducts s
ON(s.PrdID = t.PrdID)
WHERE s.CategoryID = (select p.categoryID from CategoryProducts p
INNER JOIN Products f ON(p.prdID = f.prdID)
WHERE f.barcode = 42244)
Selects all the URLS , that their users are in the same category as PrdID ->175
SELECT
p.url
FROM
Products p
JOIN
CategoryProducts cp ON cp.PrdID = p.id
// WHERE p.id = 175
GROUP BY p.url, p.Category
And if you need add comment query
SELECT p.Url, p.PrdID
FROM Products p
JOIN CategoryProduct cp
ON p.PrdID = cp.PrdID
JOIN
Category c on c.id = cp.CategoryID AND cp.PrdID =175
// you need join table Category
Show me your Category table structure

Inner join base on specific condition

There are 3 tables Brand,Product and BrandProduct respectively.Table has following structure.
Brand : id,BrandName
Product : id,ProductName
BrandProduct :id,Brandid,Productid,Prize,RetailerName
I want to display the name of product,prize and retailername.This is my query.
select ProductName,Prize,RetailerName from BrandProduct BP
inner join Product P
on P.id = BP.Productid
When user select Brand,only that's brand record should come.So I changed a query.It is working properly
create proc_sample
#Brandid int = null
as
begin
select ProductName,Prize,RetailerName from BrandProduct BP
inner join Product P
on P.id = BP.Productid
inner join Brand B
on B.id = BP.Brandid
where (#Brandid is null or BP.Brandid= #Brandid)
End
When user will not select brand,join of Brand should not come.Any Idea?I know Dynamic sql come into picture.Any alternative to dynamic sql
No need to join Brand table, because BrandProduct table contains BrandId.
select ProductName,Prize,RetailerName from BrandProduct BP
inner join Product P
on P.id = BP.Productid
where (#Brandid is null or BP.Brandid = #Brandid)