Getting extra data from the join table - sql

Ok so i have this structure
PRODUCTS
* PRODUCT_ID (primary key)
* PRODUCT_NAME
CATEGORIES
* CATEGORY_ID (primary key)
* CATEGORY_NAME
* CODE
PRODUCT_CATEGORIES_MAP
* PRODUCT_ID (primary key, foreign key to PRODUCTS)
* CATEGORY_ID (primary key, foreign key to CATEGORIES)
* QUANTITY
I am using this query
SELECT * FROM `products`
where id in (
SELECT `product_id`
FROM `categorizations`
WHERE category_id = (
SELECT id
FROM `categories`
where code = 'something'))
this works great but i am just getting a list of products. I need the quantity of each one one in the join table

The table names in your explanation are different from your sample query. I used the ones from your query.
SELECT p.product_id ,
p.product_name,
pc.quantity
FROM `products` p
JOIN `categorizations` pc
ON p.id = pc.`product_id`
JOIN `categories` c
ON c.id = pc.category_id
WHERE c.code = 'something'

sql's a bit rusty but here goes
select PRODUCT_ID, PRODUCT_NAME, QUANTITY
from PRODUCTS as A, PRODUCTS_CATEGORIES_MAP as B, CATEGORIES as C
where A.PRODUCT_ID = B.PRODUCT_ID
and C.CATEGORY_ID = B.CATEGORY_ID
and C.CODE = 'something'

You may want to sum over quantity in case product is in more categories.
select p.*,
sum(m.quantity) quantity
from products p
join categorizations m on m.product_id = p.product_id
join categories on c.category_id = m.category_id
and c.code = 'something'
group by p.product_id
Otherwise look at #Martin code

The detail that you want is the quantity of the product and so, why not start by them....you can always retrieve the products because you have the product_id.
SELECT * FROM (SELECT `product_id`, `quantity`
FROM `categorizations`
WHERE category_id = (
SELECT id
FROM `categories`
where code = 'something'))) AS `filtered_categorization`
LEFT JOIN `products`
ON (`products`.`id` == `filtered_categorization`.`product`);

try this...
select
p.*,
c.category_id,
c.category_name,
pcm.quantity
from
products p
inner join product_categories_map pcm on p.product_id = pcm.product_id
inner join categories c on pcm.category_id = c.category_id
where
c.code = 'something'
order by
p.product_id, c.category_id;

Related

Left outer joins aggregate first

I have the following tables
CREATE TABLE categories(
id SERIAL,
);
CREATE TABLE category_translations(
id SERIAL,
name varchar not null,
locale varchar not null,
category_id integer not null
);
CREATE TABLE products(
id SERIAL,
category_id integer not null
);
CREATE TABLE line_items(
id SERIAL,
total_cents integer
product_id integer not null
);
What I'm trying to do is output a map of each category name to the sum of total of its associated line_items total_cents. Something like:
name
sum_total_cents
Fresh foods
100000
Dry products
532000
There is a uniqueness constraint that only one name for each locale will be stored. So a category will have one row for each locale stored in the category_translations table
What I currently have is
SELECT SUM(line_items.total_cents) AS sum_total_cents, ???
FROM line_items INNER JOIN products ON products.id = line_items.product_id
INNER JOIN categories ON categories.id = products.category_id
LEFT OUTER JOIN category_translations ON category_translations.category_id = categories.id
WHERE category_translations.locale ='en'
GROUP BY categories.id
I'm looking for an aggregate function to return the first name for the category. The only piece missing is that what to be written instead of the ??? as I've been facing a lot of must appear in the GROUP BY clause or be used in an aggregate function errors. In pseudo-code I'm looking for a FIRST() aggregate method in PostgreSQL that I can use
Assuming you want one random name from any locale, you can do:
select
c.id,
(select name from category_translations t
where t.category_id = c.id limit 1) as name,
sum(i.total_cents) as sum_total_cents
from categories c
left join products p on p.category_id = c.id
left join line_items i on i.product_id = p.id
group by c.id, name
Alternatively, if you want the category name for the locale 'en' then you can do:
select
c.id,
(select t.name from category_translations t
where t.category_id = c.id and t.locale ='en') as name,
sum(i.total_cents) as sum_total_cents
from categories c
left join products p on p.category_id = c.id
left join line_items i on i.product_id = p.id
group by c.id, name

Customer product sale query incorrect result in sql server 2016

My DDL looks like below:
CREATE TABLE CUSTOMER
(
ID INT PRIMARY KEY,
CUSTOMER_NAME VARCHAR(50),
CITY_ID INT,
)
CREATE TABLE product
(
id int,
sku VARCHAR(50),
product_name varchar(100),
stock_qty int
)
create table Invoice
(
id int,
invoice_number varchar(100),
customer_id int
)
CREATE TABLE Invoice_item
(
id int,
invoice_id int,
product_id int,
quantity decimal(5,2),
price decimal(5,2),
line_total_price decimal(5,2)
)
I am trying to get sales details of all customer and products
output should return all customer even customer without invoices and
also all product even those product that were not sold.
I need to print customer even not have invoice and even those product
that were not sold
than customer and product as NA and quantity as o
Code i have written:
SELECT ISNULL(c.customer_name,'N/A')AS customer_name,ISNULL(p.product_name,'N/A') AS product_name,
sum(ISNULL(invitm.quantity,'0')) as quantity
FROM customer as c left outer join product as p
on c.id = p.id
left outer join invoice as inv on c.id = inv.id
left outer join invoice_item as invitm on c.id = invitm.id
group by c.customer_name,p.product_name
But this is giving incorrect result. am i doing any mistake with join. please share your suggestion
If you want all customer and product combinations, then I would suggest:
select c.customer_name, p.product_name,
coalesce(sum(ii.quantity), 0) as quantity
from customer c cross join
product p left join
invoice i
on c.id = i.customer_id left join
invoice_item ii
on ii.invoice_id = i.id and ii.product_id = p.id
group by c.customer_name, p.product_name;
If you want all customer/product combinations that exist and then extras for the customers and products that don't exist, I would suggest union all:
select c.customer_name, p.product_name,
coalesce(sum(ii.quantity), 0) as quantity
from invoice i join
customer c
on c.id = i.customer_id join
invoice_item ii
on ii.invoice_id = i.id join
product p
on ii.product_id = p.id
group by c.customer_name, p.product_name
union all
select c.customer_name, null, 0
from customer c
where not exists (select 1 from invoice i where i.customer_id = c.id)
union all
select null, p.product_name, 0
from product p
where not exists (select 1 from invoice_item ii where ii.product_id = p.id);
Maybe like this (I have not checked syntax) - all your joins were totally wrong; you need to join on corresponding fields (foreign keys), not on id-s:
SELECT ISNULL(c.customer_name,'N/A')AS customer_name,ISNULL(p.product_name,'N/A') AS product_name,
sum(ISNULL(invitm.quantity,'0')) as quantity
FROM customer as c full outer join product as p
on c.product_id = p.id
left outer join invoice as inv on c.id = inv.customer_id
left outer join invoice_item as invitm on invitm.invoice_id = inv.id and invitm.product_id = p.id
group by c.customer_name,p.product_name
This is actually a interview question. Below query might be correct:
SELECT c.customer_name,
p.product_name,
Coalesce((ii.quantity), 0) AS quantity
FROM customer c
LEFT JOIN invoice i
on c.id = i.customer_id
LEFT JOIN invoice_item ii
ON ii.invoice_id = i.id
LEFT JOIN product p
ON ii.product_id = p.id
ORDER BY c.customerid,
p.product_id,
ii.id
UNION
SELECT 'N/A',
p.product_name,
0
FROM products p ORDER p.id

List Customer And Product Without Sale

Need to show the following columns (3) using UNION to return:
All customers who do not have an invoice
All products that were not sold
Category: Is this related to "customer" or "product"? Print "customer or "product"
ID: Customer.id (category="customer") or product.id (category="product")
Name: customer.customer_name (category="customer") or product.product_name (category="product")
Tables:
Customer
id
customer_name
city_id
customer_address
contact_person
email
phone
Product
id
sku
product_name
product_description
current_price
quantity_in_stock
Invoice
id
invoice_number
customer_id
user_account_id
total_price
time_issued
time_due
time_paid
time_canceled
time_refunded
Invoice_Item
id
invoice_id
product_id
quantity
price
line_total_price
So far have the following:
SELECT
category,
CASE
WHEN category = 'customer' THEN c.id
WHEN category = 'product' THEN p.id
END AS 'id',
CASE
WHEN category = 'customer' THEN c.customer_name
WHEN category = 'product' THEN p.product_name
END AS 'name'
FROM
(
SELECT
CASE
WHEN c.id = c.id THEN 'customer'
WHEN p.id = p.id THEN 'product'
END as 'category'
FROM
customer as c
LEFT Join -- Left join to show all customers even those with & without invoices
invoice as i
ON c.id = i.customer_id
AND i.id IS NULL -- Gives me all customers who do not have an invoice
JOIN invoice_item as ii
ON i.id = ii.invoice_id
Join product p
ON p.id = ii.product_id
) tb1
UNION ALL
SELECT
category,
CASE
WHEN category = 'customer' THEN c.id
WHEN category = 'product' THEN p.id
END AS 'id',
CASE
WHEN category = 'customer' THEN c.customer_name
WHEN category = 'product' THEN p.product_name
END AS 'name'
FROM
(
SELECT
CASE
WHEN c.id = c.id THEN 'customer'
WHEN p.id = p.id THEN 'product'
END as 'category'
FROM
product as p
LEFT JOIN -- Left join to show all products even those that sold and not sold
invoice_item as ii
ON p.id = ii.product_id
AND ii.invoice_id IS NULL -- Gives me products that didnt sell
JOIN invoice as i
ON ii.invoice_id = i.id
) tb2
Open to any suggestions as I'm stuck trying to figure out how to show the category as either "product" or "customer". Thanks in advance!
Considering your data model and requirements, you should try the below SQLs. You can easily perform UNION with both the SQLs.
First SQL returns this list --> All customers who do not have an invoice
select 'customer' as category, c.id as id, customer_name as name
from customer c
left join invoice i on c.id = i.customer_id
where i.id is null
Second SQL returns this list --> All products that were not sold
select 'product' as category, p.id as id, product_name as name
from product p
left join invoice_item ii on p.id = ii.product_id
where ii.id is null;
Well, it is older than 6 months but still, answer would be:
select 'customer' as category, c.id as id, customer_name as name
from customer c
left join invoice i on c.id = i.customer_id
where i.id is null
union
select 'product' as category, p.id as id, product_name as name
from product p
left join invoice_item ii on p.id = ii.product_id
where ii.id is null;
SELECT 'customer' as category,id,customer_name FROM customer
WHERE id NOT IN(SELECT customer_id FROM invoice)
UNION
SELECT 'product' as category,id,product_name FROM product
WHERE id NOT IN(SELECT product_id FROM invoice_item);
The actual question is all customers details even those without invoices and all products even those which are not sold.
SELECT c.customer_name,
p.product_name,
Coalesce((ii.quantity), 0) AS quantity
FROM customer c
LEFT JOIN invoice i
on c.id = i.customer_id
LEFT JOIN invoice_item ii
ON ii.invoice_id = i.id
LEFT JOIN product p
ON ii.product_id = p.id
ORDER BY c.customerid,
p.product_id,
ii.id
UNION
SELECT 'N/A',
p.product_name,
0
FROM products p
ORDER BY p.id

SQL INNER JOIN entity

I want to execute this query :
-- The most expensive item sold ever
SELECT
c.itemID, c.itemName
FROM
item AS c
JOIN
(SELECT
b.itemID as 'itemid', MAX(b.item_initialPrice) AS 'MaxPrice'
FROM
buyeritem AS a
INNER JOIN
item AS b ON a.item_ID = b.itemID) AS d ON c.itemID = d.itemid
GROUP BY
c.itemID, c.itemName;
My item table looks like this:
create table item
(
itemID int IDENTITY(1000, 1) NOT NULL,
itemName varchar(15) NOT NULL,
Item_desc varchar(255),
Item_initialPrice MONEY,
ItemQty int,
ownerID int NOT NULL,
condition varchar(20) NOT NULL,
PRIMARY KEY (itemID),
FOREIGN KEY (ownerID) REFERENCES seller (sellerID)
);
The problem is that column item.itemID is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. I tried to add a group by clause at the end
group by c.itemID, c.itemName
but I still get the same error? I don't really know where the problem comes from.
I also have this query
-- The most active seller(the one who has offered the most number of items)
SELECT
a.ownerID, b.sellerName
FROM
item AS a
INNER JOIN
seller AS b ON a.ownerID = b.sellerID
GROUP BY
a.ownerID, b.sellerName
ORDER BY
COUNT(a.itemID) DESC;
I want to add itemQty along with the ownerID and sellerName from item table stated above, what would be the best way to achieve that?
Just write distinct instead of Group By as Group By will not work with out an aggregated function like sum,max etc. in select statement which is missing in your query.An example of this is second query which I have written
SELECT distinct c.itemID, c.itemName
FROM item AS c
JOIN (
SELECT b.itemID as itemid, MAX(b.item_initialPrice) AS MaxPrice FROM buyeritem AS a
INNER JOIN item AS b ON a.item_ID = b.itemID
GROUP BY b.itemID) as d
ON c.itemID = d.itemid ;
For second query
Select a.* from
(
SELECT a.ownerID, b.sellerName, count(distinct a.ITEM_ID) as item_qty
FROM item AS a
INNER JOIN seller AS b ON a.ownerID = b.sellerID
GROUP BY a.ownerID,b.sellerName
) a
order by item_qty DESC

Limit results from joined table to one row

Here is a simplified table structure:
TABLE products (
product_id INT (primary key, auto_increment),
category_id INT,
product_title VARCHAR,
etc
);
TABLE product_photos (
product_photo_id (primary key, auto_increment),
product_id INT,
photo_href VARCHAR,
photo_order INT
);
A product can have multiple photos, the first product photo for each product (based on the photo_order) is the default photo.
Now, I only need all of the photos on the product details page, but on pages where I am listing multiple products, for example a product directory page, I only want to display the default photo.
So what I am trying to do, is query a list of products including the default photo for each product.
This obviously doesn't work, it will return all photos with the product info duplicated for each photo:
SELECT p.*, ph.*
FROM products AS p
LEFT JOIN product_photos AS ph
ON p.product_id=ph.product_id
ORDER BY p.product_title ASC
I need to figure out how to do something like this, but I don't know the syntax (or if it is possible)
SELECT p.*, ph.*
FROM products AS p
LEFT JOIN product_photos AS ph
ON p.product_id=ph.product_id **ORDER BY ph.photo_order ASC LIMIT 1**
ORDER BY p.product_title ASC
Edit: I figured out a solution with help from the answers below, thanks all!
SELECT p.*, ph.*
FROM products AS p
LEFT JOIN product_photos AS ph
ON p.product_id=ph.product_id
AND ph.photo_order =
(
SELECT MIN(z.photo_order)
FROM product_photos AS z
WHERE z.product_id=p.product_id
)
GROUP BY p.product_id
ORDER BY p.product_title ASC
SELECT p.*, ph.*
FROM products AS p
INNER JOIN product_photos AS ph
ON p.product_id = ph.product_id
LEFT JOIN product_photos AS ph2
ON p.product_id = ph2.product_id
AND ph2.photo_order < ph.photo_order
WHERE ph2.photo_order IS NULL
ORDER BY p.product_title ASC
Note the how it joins to the product_photos table twice. The WHERE ph2.photo_order IS NULL will throw out all but the lowest photo order. It won't protect you against duplicate product_id / photo_orders combo though, you could add a GROUP BY on p.id if that's the case.
Use:
SELECT p.*,
pp.*
FROM PRODUCTS p
JOIN PRODUCT_PHOTOS pp ON pp.product_id = p.product_id
JOIN (SELECT x.product_id,
MIN(x.photo_order) AS default_photo
FROM PRODUCT_PHOTOS x
GROUP BY x.product_id) y ON y.product_id = pp.product_id
AND y.default_photo = pp.photo_order
SELECT p.*, ph.*
FROM products AS p
LEFT JOIN product_photos AS ph ON p.product_id=ph.product_id
ORDER BY p.product_title ASC, ph.photo_order ASC
GROUP BY p.product_id
LIMIT 0,10
SELECT ...
....
GROUP BY p.product_id