Why the payment.customer_id is wrong? - postgresql

SELECT customer.customer_id, first_name, last_name, SUM(amount)
FROM customer
INNER JOIN payment
ON customer.customer_id = payment.customer_id
GROUP BY customer.customer_id
ORDER BY customer.customer_id;
This query is giving correct answer but when I am writing
SELECT payment.customer_id, first_name, last_name, SUM(amount)
FROM customer
INNER JOIN payment
ON customer.customer_id = payment.customer_id
GROUP BY payment.customer_id
ORDER BY customer.customer_id;
It's showing up errors.

I guess that customer_id is a primary key of customer table and therefore you can select other columns from customer table when grouping by it - see https://www.postgresql.org/docs/current/sql-select.html#SQL-GROUPBY:
When GROUP BY is present, or any aggregate functions are present, it
is not valid for the SELECT list expressions to refer to ungrouped
columns except within aggregate functions or when the ungrouped column
is functionally dependent on the grouped columns, since there would
otherwise be more than one possible value to return for an ungrouped
column. A functional dependency exists if the grouped columns (or a
subset thereof) are the primary key of the table containing the
ungrouped column.

Related

Converting counts inside query result tables to percentages of total

I have a table and want to calculate the percentage of total by store_id which each (category_id, store_id) subtotal represents. My code is below:
WITH
example_table (name, store_id)
AS
(
select name, store_id
from category
join film_category using (category_id)
join film using (film_id)
join inventory using (film_id)
join rental using (inventory_id)
)
SELECT name, store_id, cast(count(*) as numeric)/(SELECT count(*) FROM example_table)
FROM example_table
GROUP BY name, store_id
ORDER BY name, store_id
This code actually works, as in, it doesn't throw an error, only they're not the results I'm looking for. Here each of the subtotals is divided by the total across both stores and all 16 names. Instead, I want the subtotals divided by their respective store totals or divided by their respective name totals.
I'm wondering how to perform calculations on those subtotals in general.
Thanks in advance,
I believe you need to explore the possibilities of using aggregate functions combined with an OVER(PARTITION BY ...) e.g.
SELECT DISTINCT
name, store_id, store_id_count, name_count
FROM (
select name, store_id
, count(*) over(partition by store_id) as store_id_count
, count(*) over(partition by name) as name_count
from category
join film_category using (category_id)
join film using (film_id)
join inventory using (film_id)
join rental using (inventory_id)
) AS example_table
When using aggregate function with the over clause you get the wanted counts on each row of the result, and it seems that in this case you need this. Note that select distinct has been used simply to reduce the final number of rows returned, you might still need to use a group by but I am not sure if you do.
Once you have the needed values within the derived table (aliases as example_table) then it should be a simple matter of some arithmetic in the overall select clause.

How to make a query with the data of another query on SQL?

I have a user table and another order table. A user can have many orders. How do I get the last 1000 users and those users use my last 1000 orders for each one?
Query - Get users
select distinct users.id, users.first_name, users.last_name
from users
limit 2;
Query - Get orders
select distinct orders.id, orders.user_id
from orders
limit 2;
First you need to know.. When it comes to query data don't do separate operation.. If you put out All Users and Orders Your data will be unordered and not consistency.. So you need to make Join to see All User with Order they have.. And as stated by #Sharon you need to add column date_ordered to see that order make.. I am assume you already have that column but i will call that column with date_ordered..
And your query will be :
select
users.id,
users.first_name,
users.last_name,
orders.id
from
users
inner join orders on users.id = orders.user_id
order by
orders.date_ordered desc
limit 1000
By order date_ordered use desc you will get the latest all the user with their order.. And i assume user_id column in table orders have constraint foreign key references to table users with column id..

Inner join with count and group by

I have 2 tables
Timetable :
pupil_id, staff_id, subject, lesson_id
Staff_info :
staff_id, surname
The timetable table contains 1000s of rows because each student's ID is listed under each period they do.
I want to list all the teacher's names, and the number of lessons they do (count). So I have to do SELECT with DISTINCT.
SELECT DISTINCT TIMETABLE.STAFF_ID,
COUNT(TIMETABLE.LESSON_ID),
STAFF.SURNAME
FROM STAFF
INNER JOIN TIMETABLE ON TIMETABLE.STAFF_ID = STAFF.STAFF_ID
GROUP BY TIMETABLE.STAFF_ID
However I get the error:
Column 'STAFF.SURNAME' is invalid in the select list because it is not
contained in either an aggregate function or the GROUP BY clause.
This should do what you want:
SELECT s.STAFF_ID, COUNT(tt.LESSON_ID),
s.SURNAME
FROM STAFF s INNER JOIN
TIMETABLE tt
ON tt.STAFF_ID = s.STAFF_ID
GROUP BY s.STAFF_ID, s.SURNAME;
Notes:
You don't need DISTINCT unless there are duplicates in either table. That seems unlikely with this data structure, but if a staff member could have two of the same lesson, you would use COUNT(DISTINCT tt.LESSON_ID).
Table aliases make the query easier to write and to read.
You should include STAFF.SURNAME in the GROUP BY as well as the id.
I have a preference for taking the STAFF_ID column from the table where it is the primary key.
If you wanted staff with no lessons, you would change the INNER JOIN to LEFT JOIN.
SELECT T.STAFF_ID,
T.CNT,
S.SURNAME
FROM STAFF S
JOIN (
SELECT STAFF_ID, CNT = COUNT(/*DISTINCT*/ LESSON_ID)
FROM TIMETABLE
GROUP BY STAFF_ID
) T ON T.STAFF_ID = S.STAFF_ID
Another option:
SELECT DISTINCT si.staff_id, surname, COUNT(lesson_id) OVER(PARTITION BY staff_Id)
FROM Staff_info si
INNER JOIN Timetable tt ON si.staff_id = tt.staff_id
When using Aggregate function(Count, Sum, Min, Max, Avg) in the Select column's list, any other columns that are in the Select column's list but not in a aggregate function, should be mentioned in GROUP BY section too. So you need to change your query as follow and add STAFF.SURNAME to GROUP BY section too:
SELECT TIMETABLE.STAFF_ID,
COUNT(TIMETABLE.LESSON_ID),
STAFF.SURNAME
FROM STAFF
INNER JOIN TIMETABLE ON TIMETABLE.STAFF_ID = STAFF.STAFF_ID
GROUP BY TIMETABLE.STAFF_ID,STAFF.SURNAME
Distinct is useless also in your scenario. and also as you are going to show the teachers name and Count lessons, you do not need to add TIMETABLE.STAFF_ID to Select's column's list,, but it should remain in Group By section to prevent duplicate names.
SELECT COUNT(TIMETABLE.LESSON_ID),
STAFF.SURNAME
FROM STAFF
INNER JOIN TIMETABLE ON TIMETABLE.STAFF_ID = STAFF.STAFF_ID
GROUP BY TIMETABLE.STAFF_ID,STAFF.SURNAME
You may need to take a look at this W3C post for more info

Show field in MS Access query without including it in the group by clause

I'm working on a query that will eventually be used as the record source for a report.
I have a customers and orders table. I want to show customer_id, order_id, and order_date in a query, but I only want to show data associated with the earliest order date for each customer. Basically, I need to show the order_id field without including it in the group by clause. If I include it in the group by clause, I get a lot more records than I want. Based on my research, the code below will work in mysql, but not ms access.
Select customer.customer_id, order.order_id, min(order.order_dt)
From customer inner join order on customer.customer_id = order.customer_id
Group by customer.customer_id
I've tried grouping by order_id in a sub query and ordering by customer then date, then using the first function in the outer query. Unfortunately, the first function doesn't work as advertised.
Any help is greatly appreciated!
Does this work for you? It should bring up the earliest orders by order date for each customer. If there is more than one order on the earliest order date for a customer, all of those orders will be shown, though, so keep it in mind.
SELECT c.customer_id, o.order_id, o.order_dt
FROM customers AS c INNER JOIN (orders AS o INNER JOIN (SELECT customer_ID, MIN([order_dt]) AS MinOrder_dt FROM Orders GROUP BY customer_id) AS d ON (o.Customer_ID = d.customer_id) AND (o.[order_dt] = d.MinOrder_dt)) ON c.customer_id = o.customer_id;
I am deriving a table with just the customer_id and the min order_dt and joining customers and orders to that to only bring up the oldest orders.

PostgreSQL: Select first row as column inside select

I got 2 tables like Customers and Orders, in table Customers I got columns id, name, in table Orders I got columns id, customer_id, order_date.
Now I need to make one select that will return me each Customer's id, name and the last order_date.
I tried to make like this:
select
Customers.id,
Customers.name,
(select Orders.order_date from Orders where Orders.customer_id = Customer.id order by order_date desc) as last_order_date
from
Customers
But it get the wrong index and takes forever to execute.
Whats the best way to make this select in PostgreSQL?
Thanks in advanced.
If not restricting by customer_id, then the query will end up having to scan the entire orders table.
SELECT c.id
,c.name
,MAX(o.order_date) AS last_order_date
FROM Customers c
LEFT OUTER JOIN Orders o ON (o.customer_id = c.id)
GROUP BY c.id, c.name