ORDER BY id IN Subquery - sql

I have a query like this:
SELECT i.*
FROM items i
WHERE i.id
IN (
SELECT c.item_id
FROM cart c
WHERE c.sessID=MY_SESSION_ID
)
It's working beautifully, but I need to sort items from the cart by date of purchase (cart.id) DESC.
I don't want sort in PHP. How can I sort by cart.id?
I tried:
SELECT i.*
FROM items i
WHERE i.id
IN (
SELECT c.item_id
FROM cart c
WHERE c.sessID=MY_SESSION_ID
)
ORDER BY c.id
But it did not sort correctly.

Change your Sub query to Inner Join. Sub query will not allow to you refer the columns outside of sub query. So change it to Inner join
SELECT i.*
FROM items i
JOIN (SELECT item_id,
id
FROM cart) C
ON i.id = c.item_id
AND c.sessID = MY_SESSION_ID
ORDER BY c.id Desc
or use this.
SELECT i.*
FROM items i
JOIN cart C
ON i.id = c.item_id
AND c.sessID = MY_SESSION_ID
ORDER BY c.id Desc

Try this query:
SELECT i.* FROM items i LEFT OUTER JOIN cart c
ON i.id = c.item_id WHERE c.sessID=MY_SESSION_ID AND
c.item_id is not null ORDER BY c.id

Try this:
SELECT i.*
FROM items i
INNER JOIN cart c ON i.id = c.item_id
WHERE c.sessID = MY_SESSION_ID
GROUP BY i.id
ORDER BY MAX(c.id) DESC;
OR
SELECT i.*
FROM items i
INNER JOIN (SELECT item_id, MAX(id) AS cid
FROM cart
WHERE sessID = MY_SESSION_ID
GROUP BY item_id
) AS c ON i.id = c.item_id
ORDER BY c.cid DESC;

Related

SELECT * and SELECT COUNT(*) in one query

My SQL query looks like this
SELECT *
FROM categories AS c
LEFT JOIN LATERAL (SELECT i.*
FROM influencer_profiles AS i
WHERE c.id = i.category_id
ORDER BY i.updated_at
LIMIT 2) AS i ON 1 = 1
INNER JOIN users AS u ON i.user_id = u.id
But I also want to count each influencer_profile for category to display how many influencer_profiles in each categories. How can I use COUNT(*) with selecting all columns?
SELECT *
FROM categories AS c
LEFT JOIN LATERAL (SELECT COUNT(*)
FROM influencer_profiles AS i
WHERE c.id = i.category_id
ORDER BY i.updated_at
LIMIT 2) AS i ON 1 = 1
INNER JOIN users AS u ON i.user_id = u.id
This code doesn't work.
Perhaps you just want a window function. I note that you are using left join in one place and the inner join is undoing it.
So, I am thinking:
SELECT c.*, i.*, u.*,
COUNT(*) OVER (PARTITION BY c.id) as category_cnt
FROM categories c LEFT JOIN LATERAL
(SELECT i.*
FROM influencer_profiles AS i
WHERE c.id = i.category_id
ORDER BY i.updated_at
LIMIT 2
) i
ON 1=1 LEFT JOIN
users u
ON i.user_id = u.id;

How to add TOP 1 in query with left join in views?

I have 3 same product in ID=42, with 3 different images. I want to take the first image from the product ID, I try adding "TOP 1", error
This is my query
CREATE OR REPLACE VIEW UserOrdersView
AS
SELECT
u.[User_ID],
p.Product_Name,
p.Price,
o.Order_Price,
o.Order_ID,
i.[Image]
FROM Product p
LEFT JOIN Orders o ON o.Product_ID = p.Product_ID
INNER JOIN Users u ON u.[User_ID]= o.[User_ID]
LEFT JOIN Product_Images i ON i.Product_ID = p.Product_ID
WHERE o.[User_ID] = 42
You need to use OUTER APPLY to get top 1 image data from Product_image table based on Product ID.
Please check this Real life example, when to use OUTER / CROSS APPLY in SQL stackoverflow link for more knowledge.
Please check below updated view code for your answer.
CREATE OR REPLACE VIEW UserOrdersView
AS
BEGIN
SELECT
u.[User_ID],
p.Product_Name,
p.Price,
o.Order_Price,
o.Order_ID,
i.[Image]
FROM Product p
INNER JOIN Users u ON u.[User_ID]= o.[User_ID]
LEFT JOIN Orders o ON o.Product_ID = p.Product_ID
OUTER APPLY
(
SELECT TOP 1
T2.[Image]
FROM Product_Images T2
WHERE T2.Product_ID = p.Product_ID
) i
WHERE o.[User_ID] = 42
END
GO
WITH cte as (
SELECT
u.[User_ID],
p.Product_Name,
p.Price,
o.Order_Price,
o.Order_ID,
i.[Image],
ROW_NUMBER() OVER (PARTITION BY i.[Image] ORDER BY p.Product_Name) AS rn
FROM Product p
LEFT JOIN Orders o ON o.Product_ID = p.Product_ID
INNER JOIN Users u ON u.[User_ID]= o.[User_ID]
LEFT JOIN Product_Images i ON i.Product_ID = p.Product_ID
)
SELECT [User_ID],Product_Name,Price,Order_Price,Order_ID,[Image] FROM cte
WHERE rn=1
Put your all query inside a CTE with a new column that you will use to filter the results.
This new column is produced with ROW_NUMBER() function partitioned by Product_Name

Sql Query for Identified by duplicates and remove in it

SELECT i.product_id, o.date_added
FROM ims_order_product i
INNER JOIN ims_order o
WHERE i.product_id IN (SELECT p.product_Id FROM ims_product p)
The Query Return Product_id column and Date column But Product_id column contain duplicates So I want remove duplicates in Product_id based on Date_added by recent Date Can any give the answer.
Try grouping by product_id. Below query will select the latest date for duplicate product_id
SELECT i.product_id, MAX(o.date_added) FROM ims_order_product i INNER JOIN ims_order o WHERE i.product_id IN (SELECT p.product_Id FROM ims_product p) GROUP BY i.product_id
Please try this query
SELECT i.product_id, MAX(o.date_added) date_added
FROM ims_order_product i
INNER JOIN ims_order o --add your join condition here
WHERE EXISTS (SELECT p.product_Id FROM ims_product p WHERE p.product_Id = i.product_id)
GROUP BY i.product_id
SELECT * FROM (SELECT i.product_id, o.date_added, o.order_id FROM ims_order_product i
JOIN ims_order o ON o.order_id = i.order_id
JOIN ims_product pr ON pr.product_id = i.product_id ORDER BY date_added DESC) AS sub GROUP BY product_id

Left outer join with only first row

I have a query something like
SELECT S.product_id, S.link, C.id AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
LEFT OUTER JOIN Categories C ON c.product_id = P.id
WHERE P.active = 1
I works fine for me as long as each product has assigned to only one category. But if a product is assigned to many categories it returns all possible combinations.
Can I only select the first one and if a product don't have any category the link should still be returned with category_id = NULL
An easy way is to use outer apply, so as to have a correlated join, and make that a top 1 query. Thus you are able to access all columns of the category record in question. I'm adding a category name here as an example:
select s.product_id, s.link, c.id as category_id, c.name as category_name
from products p
inner join seo s on s.product_id = p.id
outer apply
(
select top 1 *
from categories cat
where cat.product_id = p.id
order by cat.id
) c
where p.active = 1
and p.product_type = 1;
You can use a GROUP BY to accomplish this along with an Aggregate function, most likely MIN or MAX.
Depending on which Category Id you prefer in your result you could select the minimum.
SELECT S.product_id, S.link, MIN(C.id) AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
LEFT OUTER JOIN Categories C ON c.product_id = P.id
WHERE P.active = 1
GROUP BY S.product_id, S.link
Or the maximum.
SELECT S.product_id, S.link, MAX(C.id) AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
LEFT OUTER JOIN Categories C ON c.product_id = P.id
WHERE P.active = 1
GROUP BY S.product_id, S.link
Alternate solution using subquery:
SELECT S.product_id, S.link,
(
SELECT C.id FROM Categories C WHERE C.product_id = P.id AND
ROW_NUMBER() OVER(ORDER BY /* your sort option goes here*/ ) = 1
) AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
WHERE P.active = 1

Joining three tables with aggregation

I have the following items table:
items:
id pr1 pr2 pr3
-------------------
1 11 22 tt
...
and two tables associated with the items:
comments:
item_id text
-------------
1 "cool"
1 "very good"
...
tags:
item_id tag
-------------
1 "life"
1 "drug"
...
Now I want to get a table with columns item_id, pr1, pr2, count(comments), count(tags) with a condition WHERE pr3 = zz. What is the best way to get it? I can do this by creating additional tables, but I was wondering if there is a way achieve this by using only a single SQL statement. I'm using Postgres 9.3.
The easiest way is certainly to get the counts in the select clause:
select
id,
pr1,
pr2,
(select count(*) from comments where item_id = items.id) as comment_count,
(select count(*) from tags where item_id = items.id) as tag_count
from items;
You can just join, but you need to be careful that you don't get double count. E.g. you can use a subqueries to get what you want.
SELECT i.id,i.pr1,i.pr2, commentcount,tagcount FROM
items i
INNER JOIN
(SELECT item_id,count(*) as commentcount from comments GROUP BY item_id) c
ON i.id = c.item_id
INNER JOIN
(SELECT item_id,count(*) as tagcount from tags GROUP BY item_id) t
ON i.id = t.item_id
[EDIT] based on the comment, here's the left join version...
SELECT i.id,i.pr1,i.pr2, coalesce(commentcount,0) as commentcount,
coalesce(tagcount,0) as tagcount FROM
items i
LEFT JOIN
(SELECT item_id,count(*) as commentcount from comments GROUP BY item_id) c
ON i.id = c.item_id
LEFT JOIN
(SELECT item_id,count(*) as tagcount from tags GROUP BY item_id) t
ON i.id = t.item_id
Try this:
SELECT i.id, i.pr1, i.pr2, A.commentCount, B.tagCount
FROM items i
LEFT OUTER JOIN (SELECT item_id, COUNT(1) AS commentCount
FROM comments
GROUP BY item_id
) AS A ON i.id = A.item_id
LEFT OUTER JOIN (SELECT item_id, count(1) as tagCount
FROM tags
GROUP BY item_id
) AS B ON i.id = B.item_id;
select
i.id
, i.pr1
, i.pr2
, count(c.item_id) as count_comments
, count(t.item_id) as count_tags
from items i
left outer join comments c on i.id = c.item_id
left outer join tags t on i.id = t.item_id
group by i.id, i.pr1, i.pr2
I've used a LEFT OUTER JOIN to also return counts of zero.