I've been searching for 2 hours on how to build a query with eloquent using groupBy and orderBY.
This is my situation: I have a table orders with these columns:
idOfOrder, quantityOfProduct, userWhoBuy, productBuy, statusOfOrder
I would like to get the 3 most sold products. For this, I need to build a query who group all data from ProductBy, sum theme from quantity and sort theme by desc. But it's terribly difficult.
This my actual query:
$buyObj->select('product',DB::raw('count(*) as total'))
->where('status','=','1')
->groupBy('product')
->orderBy('quantity','desc')
->take(3)
->get();
I get this error :
SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'web_projet_exia.buys.quantity' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by (SQL: select product, count(*) as total from buys where status = 1 group by product order by quantity desc limit 3) "
Do you know how to fix that ?
Thanks in advance !
The solution is just to order by total and not by quantity. Thanks to #JonasStaudenmeir
Related
I have a table where I try to aggreate results (Sum) based on all possible combinations of Product_Ids per Order (Order_Id). Anybody that can guide me here?
I'm a bit lost here, but I have tried to group the different combinations but don't manage to get the right results.
I think you would like to group the results by order_id:
select array_agg(distinct product_id), sum(summ) total
from stat
group by order_id
order by total desc;
The function array_agg(distinct product_id) helps to concatenate unique values of product_id grouping values by order_id.
See the demo with all the details.
I was trying to write a postgresql statement that would allow me to execute a certain query only if a condition is satisfied:
select SUM("TotalBookings") AS Availability,
from (select count (*) as "TotalBookings"
from bookings
where hotel_id=2 and ('2023-02-10') between symmetric check_in_date and check_out_date
union all
select -count (*) as "TotalRooms"
from hotels
inner join rooms on rooms.hotel_id = hotels.hotel_id
where hotels.hotel_id=2 ) Availability;
case
when Availability >= 1
then select *
from hotels
where hotel_id=2
end
I basically would like to show my hotels only when the sum is greater than one.
Below the error returned:
syntax error at or near "from"
Any ideas on whether mine is only a syntax error or if my logic is wrong as well ?
Thank you in advance.
For Example:
SELECT * FROM Customers
WHERE Country IN ('Germany', 'France', 'UK')
I want to LIMIT 1 for each of the countries in my IN clause so I only see a total of 3 rows: One customer for per country (1 German, 1 France, 1 UK). Is there a simple way to do that?
Normally, a simple GROUP BY would suffice for this type of solution, however as you have specified that you want to include ALL of the columns in the result, then we can use the ROW_NUMBER() window function to provide a value to filter on.
As a general rule it is important to specify the column to sort on (ORDER BY) for all windowing or paged queries to make the result repeatable.
As no schema has been supplied, I have used Name as the field to sort on for the window, please update that (or the question) with any other field you would like, the PK is a good candidate if you have nothing else to go on.
SELECT * FROM
(
SELECT *
, ROW_NUMBER() OVER(PARTITION BY Country ORDER BY Name) AS _rn
FROM Customers
WHERE Country IN ('Germany', 'France', 'UK')
)
WHERE _rn = 1
The PARTITION BY forces the ROW_NUMBER to be counted across all records with the same Country value, starting at 1, so in this case we only select the rows that get a row number (aliased as _rn) of 1.
The WHERE clause could have been in the outer query if you really want to, but ROW_NUMBER() can only be specified in the SELECT or ORDER BY clauses of the query, so to use it as a filter criteria we are forced to wrap the results in some way.
I have a question about the right way of writing the query.
I have an employees table, lets say there are 4 columns employee_id, department, salary, email.
There are some records without email address, I'd like to find the most efficient way to write SQL query using window function that brings the sum salary per group, divided by all of those without email address.
I have 2 solutions, of course only one is efficient, can anyone give any advice about it?
select department, sum(salary) as total
from employees
where email is null
group by 1
option 1
select a.department , a.total/(select sum(salary) from employees where email is null)
from (
select department, sum(salary) as total
from employees
where email is null
group by 1
) a
option 2
select a.department , a.total/sum(a.total) over()
from (
select department, sum(salary) as total
from employees
where email is null
group by 1
) a
I guess that query 2 is more efficient, but is it the right way? and is it valid to leave over clause empty?
Just started using PostgreSQL instead of MySQL 5.6.
Your second query is better.
The first query has to scan employees twice, while the second table only scans the (hopefully smaller) result set of the subquery to calculate the sum.
It is perfectly valid to leave the OVER clause empty, that just means that all result rows will get the same value (which is what you want).
I'm getting an error running this query
SELECT date(updated_at), count(updated_at) as total_count
FROM "persons"
WHERE ("persons"."updated_at" BETWEEN '2012-10-17 00:00:00.000000' AND '2012-11-07 12:25:04.082224')
GROUP BY date(updated_at)
ORDER BY persons.updated_at DESC
I get the error ERROR: column "persons.updated_at" must appear in the GROUP BY clause or be used in an aggregate function LINE 5: ORDER BY persons.updated_at DESC
This works if I remove the date( function from the group by call, however I'm using the date function because i want to group by date, not datetime
any ideas
At the moment it is unclear what you want Postgres to return. You say it should order by persons.updated_at but you do not retrieve that field from the database.
I think, what you want to do is:
SELECT date(updated_at), count(updated_at) as total_count
FROM "persons"
WHERE ("persons"."updated_at" BETWEEN '2012-10-17 00:00:00.000000' AND '2012-11-07 12:25:04.082224')
GROUP BY date(updated_at)
ORDER BY count(updated_at) DESC -- this line changed!
Now you are explicitly telling the DB to sort by the resulting value from the COUNT-aggregate. You could also use: ORDER BY 2 DESC, effectively telling the database to sort by the second column in the resultset. However I highly prefer explicitly stating the column for clarity.
Note that I'm currently unable to test this query, but I do think this should work.
the problem is that, because you are grouping by date(updated_at), the value for updated_at may not be unique, different values of updated_at can return the same value for date(updated_at). You need to tell the database which of the possible values it should use, or alternately use the value returned by the group by, probably one of
SELECT date(updated_at) FROM persons GROUP BY date(updated_at)
ORDER BY date(updated_at)
or
SELECT date(updated_at) FROM persons GROUP BY date(updated_at)
ORDER BY min(updated_at)