PostgreSQL Order By SubQuery - sql

I have this database structure:
Tables:
Category
id | category
1 | fruit
2 | cars
3 | tables
Product
id | product | category_id
1 | banana | 1
2 | apple | 1
3 | orange | 1
4 | example 1 | 2
5 | example 2 | 3
User_List
id | product_id | user_id | bought_date
1 | 1 | 1 | 2012-06-21 11:00:00
2 | 2 | 1 | 2012-06-21 06:00:00
3 | 4 | 1 | 2012-06-21 08:00:00
4 | 5 | 1 | 2012-06-21 01:00:00
what i want is create a query that "order by bought_date (desc) by category".
In that case the expected result is:
banana
apple
example 1
example 2
My query:
SELECT c.id, u.bought_date
FROM categry as c
left join product p on (c.id=p.category_id)
left join user_list u on (p.id=u.product_id)
WHERE u.user_id=3
ORDER BY u.bought_date DESC NULLS LAST
But this only does a simple sort by bought date...
with this result:
banana
example 1
apple
example 2

I thought of one ordering. You want to order by the earliest or latest date for each category. For that, use window functions.
SELECT c.id, u.bought_date, max(u.bought_date) over (partition by c.id) as category_bd
FROM categry c left join
product p
on (c.id=p.category_id) left join
user_list u
on (p.id=u.product_id)
WHERE u.user_id = 3
ORDER BY category_bd DESC NULLS LAST, u.bought_date DESC NULLS LAST

It sounds as though you just need two columns in your order by clause:
SELECT c.id, u.bought_date
FROM categry as c
left join product p on (c.id=p.category_id)
left join user_list u on (p.id=u.product_id)
WHERE u.user_id=3
ORDER BY category_id, u.bought_date DESC NULLS LAST

Assuming missing information:
bought_date is defined NOT NULL.
There can be multiple rows in user_list per product, and they can have a different bought_date.
Order products by the latest bought_date of their category first,
and by their latest bought_date next.
SELECT p.product
FROM product p
JOIN user_list u ON u.product_id = p.id
GROUP BY 1
ORDER BY max(max(u.bought_date)) OVER (PARTITION BY p.category_id) DESC
, max(u.bought_date) DESC;
You don't need the table categry in the query at all.
The window function to get the latest bought_date per category can go into the ORDER BY clause.
Yes, that's a window function over the aggregate max(u.bought_date).
Obviously you don't want oranges in the result, since nobody "brought" them.
Use JOIN, not LEFT JOIN.

Related

sql date subquery get the last

I have an error "could not be bound" while trying this SQL
SELECT
promotions.id_product, price.value
FROM
promotions
LEFT OUTER JOIN
(SELECT TOP 1 id_product, date, value
WHERE date > promotions.date) AS price ON price.id_product = promotion.id_product
About the SQL... I have two tables and I need get the correct price while the promotions is running (not the last price)...
Table promotions
id_product | DATE | VALUE | Finish_date
1 | 2018-05-01 | 20 | 2018-06-03
1 | 2018-07-02 | 18 | 2018-08-01
Table prices
id_product | DATE | VALUE
1 | 2018-04-01 | 30
1 | 2018-06-02 | 25
You a subquery with join cannot be correlated to other tables in the from clause.
Instead, use outer apply:
SELECT p.id_product, pr.value
FROM promotions p OUTER APPLY
(SELECT TOP 1 pr.id_product, pr.date, pr.value
FROM prices pr
WHERE pr.id_produto = p.id_produto AND pr.date > p.date
ORDER BY pr.date DESC
) pr;
I added the ORDER BY. Presumably, you want the "next" price after the promotion date, not an arbitrary price afterwards.

GROUP BY with SUM without removing empty (null) values

TABLES:
Players
player_no | transaction_id
----------------------------
1 | 11
2 | 22
3 | (null)
1 | 33
Transactions
id | value |
-----------------------
11 | 5
22 | 10
33 | 2
My goal is to fetch all data, maintaining all the players, even with null values in following query:
SELECT p.player_no, COUNT(p.player_no), SUM(t.value) FROM Players p
INNER JOIN Transactions t ON p.transaction_id = t.id
GROUP BY p.player_no
nevertheless results omit null value, example:
player_no | count | sum
------------------------
1 | 2 | 7
2 | 1 | 10
What I would like to have is mention about the empty value:
player_no | count | sum
------------------------
1 | 2 | 7
2 | 1 | 10
3 | 0 | 0
What do I miss here?
Actually I use QueryDSL for that, but translated example into pure SQL since it behaves in the same manner.
using LEFT JOIN and coalesce function
SELECT p.player_no, COUNT(p.player_no), coalesce(SUM(t.value),0)
FROM Players p
LEFT JOIN Transactions t ON p.transaction_id = t.id
GROUP BY p.player_no
Change your JOIN to a LEFT JOIN, then add IFNULL(value, 0) in your SUM()
left join keeps all the rows in the left table
SELECT p.player_no
, COUNT(*) as count
, SUM(isnull(t.value,0))
FROM Players p
LEFT JOIN Transactions t
ON p.transaction_id = t.id
GROUP BY p.player_no
You might be looking for count(t.value) rather than count(*)
I'm just offering this so you have a correct answer:
SELECT p.player_no, COUNT(t.id) as [count], COALESCE(SUM(t.value), 0) as [sum]
FROM Players p LEFT JOIN
Transactions t
ON p.transaction_id = t.id
GROUP BY p.player_no;
You need to pay attention to the aggregation functions as well as the JOIN.
Please Try This:
SELECT P.player_no,
COUNT(*) as count,
SUM(isnull(T.value,0))
FROM Players P
LEFT JOIN Transactions T
ON P.transaction_id = T.id
GROUP BY P.player_no
Hope this helps.

SQL QUERY USING POSTGRESQL

I have the following query:
SELECT DISTINCT "stylists".* FROM "stylists"
INNER JOIN "category_stylists" ON "category_stylists"."stylist_id" = "stylists"."id"
WHERE category_stylists.category_id IN (1,2)
But I want to order the stylists by categories.
For example:
Stylists
id | Name
1 Sebastian
2 Jhon
Categories
id | Name
1 Wedding
2 Office
Stylist_Categories
id | stylist_id | category_id
1 1 1
2 2 1
3 2 2
So If I apply my query, I got both Stylists, but I need always order by how many categories has the stylist. I mean in this example Jhon will be the first row because has the category_id 1 and category_id 2.
Result expected:
Stylists
id | Name
2 Jhon
1 Sebastian
Thanks in advance!
Try counting categories for each stylist and order by it:
SELECT "id","name" from(
SELECT "stylists"."id", "stylists"."Name",count(stylists.id) as cnt FROM "stylists"
INNER JOIN "category_stylists" ON "category_stylists"."stylist_id" = "stylists"."id"
WHERE category_stylists.category_id IN (1,2)
group by "stylists"."id", "stylists"."Name")
order by cnt desc

PostgreSQL Referencing Outer Query in Subquery

I have two Postgres tables (really, more than that, but simplified for the purpose of the question) - one a record of products that have been ordered by customers, and another a historical record of prices per customer and a date they went into effect. Something like this:
'orders' table
customer_id | timestamp | quantity
------------+---------------------+---------
1 | 2015-09-29 16:01:01 | 5
1 | 2015-10-23 14:33:36 | 3
2 | 2015-10-19 09:43:02 | 7
1 | 2015-11-16 15:08:32 | 2
'prices' table
customer_id | effective_time | price
------------+---------------------+-------
1 | 2015-01-01 00:00:00 | 15.00
1 | 2015-10-01 00:00:00 | 12.00
2 | 2015-01-01 00:00:00 | 14.00
I'm trying to create a query that will return every order and its unit price for that customer at the time of the order, like this:
desired result
customer_id | quantity | price
------------+----------+------
1 | 5 | 15.00
1 | 3 | 12.00
2 | 7 | 14.00
1 | 2 | 12.00
This is essentially what I want, but I know that you can't reference an outer query inside an inner query, and I'm having trouble figuring out how to re-factor:
SELECT
o.customer_id,
o.quantity,
p.price
FROM orders o
INNER JOIN (
SELECT price
FROM prices x
WHERE x.customer_id = o.customer_id
AND x.effective_time <= o.timestamp
ORDER BY x.effective_time DESC
LIMIT 1
) p
;
Can anyone suggest the best way to make this work?
Instead of joining an inline view based on the prices table, you can perform a subquery in the SELECT list:
SELECT customer_id, quantity, (
SELECT price
FROM prices p
WHERE
p.customer_id = o.customer_id
AND p.effective_time <= o.timestamp
ORDER BY p.effective_time DESC
LIMIT 1
) AS price
FROM orders o
That does rely on a correlated subquery, which could be bad for performance, but with the way your data are structured I doubt there's a substantially better alternative.
You dont need the subquery, just a plain inner join will do (this assumes there are no duplicate effective_times per customer):
SELECT o.customer_id, o.quantity
,p.price
FROM orders o
JOIN prices p ON p.customer_id = o.customer_id
AND p.effective_time <= o.timestamp
AND NOT EXISTS ( SELECT * FROM prices nx
WHERE nx.customer_id = o.customer_id
AND nx.effective_time <= o.timestamp
AND nx.effective_time > p.effective_time
)
;

Select distinct where date is max

This feels really stupid to ask, but i can't do this selection in SQL Server Compact (CE)
If i have two tables like this:
Statuses Users
id | status | thedate id | name
------------------------- -----------------------
0 | Single | 2014-01-01 0 | Lisa
0 | Engaged | 2014-01-02 1 | John
1 | Single | 2014-01-03
0 | Divorced | 2014-01-04
How can i now select the latest status for each person in statuses?
the result should be:
Id | Name | Date | Status
--------------------------------
0 | Lisa | 2014-01-04 | Divorced
1 | John | 2014-01-03 | Single
that is, select distinct id:s where the date is the highest, and join the name. As bonus, sort the list so the latest record is on top.
In SQL Server CE, you can do this using a join:
select u.id, u.name, s.thedate, s.status
from users u join
statuses s
on u.id = s.id join
(select id, max(thedate) as mtd
from statuses
group by id
) as maxs
on s.id = maxs.id and s.thedate = maxs.mtd;
The subquery calculates the maximum date and uses that as a filter for the statuses table.
Use the following query:
SELECT U.Id AS Id, U.Name AS Name, S.thedate AS Date, S.status AS Status
FROM Statuses S
INNER JOIN Users U on S.id = U.id
WHERE S.thedate IN (
SELECT MAX(thedate)
FROM statuses
GROUP BY id);