Which product is ordered most frequently? - sql

SELECT ProductID
FROM OrderLine_T
GROUP BY ProductID
ORDER BY COUNT(ProductID) DESC
I'm ordering the products like this but LIMIT or ROWNUM is not functioning for some reason. I need to have a query with only the single most frequently ordered product. Im Using Teradata and the database name is db_pvfc10_big . Im sorry for the confusing question its my first question and im a beginner in using SQL
Thank you in advance

The LIMIT keyword is a MySQL-specific extension to the standard.
And ROWNUM is a pseudo column specific to Oracle.
So there are definitely "some reasons" that you might observe LIMIT and ROWNUM as "not functioning".
The question doesn't indicate which RDBMS is being used... MySQL, PostgreSQL, Oracle, SQL Server, DB2, Teradata, etc.
(NOTE: using "not functioning" as the only description of the behavior you observe is rather imprecise.
The description doesn't indicate whether the execution of the query is returning an error of some kind, or if the query is executing and returning a resultset that isn't expected.
The statement(s) you describe as "not functioning" aren't even shown.
One ANSI-standard SQL approach to getting a result is getting that "maximum" value using the standard MAX() aggregate. One way to do that is using an inline view. For example:
SELECT MAX(s.cnt) AS max_cnt
FROM ( SELECT COUNT(t.productid) AS cnt
FROM orderline_t t
GROUP BY t.productid
) s
That can also be used as an inline view...
SELECT MAX(q.productid)
FROM ( SELECT MAX(s.cnt) AS max_cnt
FROM ( SELECT COUNT(t.productid) AS cnt
FROM orderline_t t
GROUP BY t.productid
) s
) r
JOIN ( SELECT p.productid
, COUNT(p.productid) AS cnt
FROM orderline_t p
GROUP BY p.product_id
) q
ON q.cnt = r.max_cnt
Note that if there are two or more products that are ordered the same "maximum" number of times, this query will return just one of those productid.
This should work in most relational databases.
There are other query patterns that will return an equivalent result.
But this example should help explain why most RDBMS offer extensions to the SQL standard, which often make for simpler queries.
MySQL "... ORDER BY ... LIMIT 1"
SQL Server "SELECT TOP 1 ..."
etc.

You could try including the count(ProductID) in the select statement. Some sql databases use the keyword "top" instead of "limit". So if you're using one of those (like Teradata sql for example), do the following:
select top 1 ProductID, count(ProductID)
from OrderLine_T
group by ProductID
order by 2 desc;

Related

SQL query missing select statement fetching data error

I am using SQL query fetching some issue data is not fetching black show.
I am sharing this query here. Please help me.
SQL query here
select * from products where hitproduct='0' ORDER BY id DESC and user_id='$user_id'
A SQL query only has one where clause. Presumably, you intend:
select p.*
from products p
where user_id = ? and
hitproduct = 0 -- looks like a number, so I assume it is
order by id desc;
Note the use of ?. This represents a parameter placeholder. Don't munge query strings with parameters values! Learn to use parameters properly.
In your given query and user_id='$user_id' should be before ORDER BY.
select *
from products
where hitproduct='0' and user_id='$user_id'
ORDER BY id DESC

Oracle subquery in select

I have a table that keeps costs of products. I'd like to get the average cost AND last buying invoice for each product.
My solution was creating a sub-select to get last buying invoice but unfortunately I'm getting
ORA-00904: "B"."CODPROD": invalid identifier
My query is
SELECT (b.cod_aux) product,
-- here goes code to get average cost,
(SELECT round(valorultent, 2)
FROM (SELECT valorultent
FROM pchistest
WHERE codprod = b.codprod
ORDER BY dtultent DESC)
WHERE ROWNUM = 1)
FROM pchistest a, pcembalagem b
WHERE a.codprod = b.codprod
GROUP BY a.codprod, b.cod_aux
ORDER BY b.cod_aux
In short what I'm doing on sub-select is ordering descendantly and getting the first row given the product b.codprod
Your problem is that you can't use your aliased columns deeper than one sub-query. According to the comments, this was changed in 12C, but I haven't had a chance to try it as the data warehouse that I use is still on 11g.
I would use something like this:
SELECT b.cod_aux AS product
,ROUND (r.valorultent, 2) AS valorultent
FROM pchistest a
JOIN pcembalagem b ON (a.codprod = b.codprod)
JOIN (SELECT valorultent
,codprod
,ROW_NUMBER() OVER (PARTITION BY codprod
ORDER BY dtultent DESC)
AS row_no
FROM pchistest) r ON (r.row_no = 1 AND r.codprod = b.codprod)
GROUP BY a.codprod, b.cod_aux
ORDER BY b.cod_aux
I avoid sub-queries in SELECT statements. Most of the time, the optimizer wants to run a SELECT for each item in the cursor, OR it does some crazy nested loops. If you do it as a sub-query in the JOIN, Oracle will normally process the rows that you are joining; normally, it is more efficient. Finally, complete your per item functions (in this case, the ROUND) in the final product. This will prevent Oracle from doing it on ALL rows, not just the ones you use. It should do it correctly, but it can get confused on complex queries.
The ROW_NUMBER() OVER (PARTITION BY ..) is where the magic happens. This adds a row number to each group of CODPRODs. This allows you to pluck the top row from each CODPROD, so this allows you to get the newest/oldest/greatest/least/etc from your sub-query. It is also great for filtering duplicates.

SQL SUM with GROUP clause giving errors

I've been visiting this site for a while now and many of the responses on here has been most helpful. However, I'm now stuck with an SQL that I can't seem to find just the right solution for.
(the $packplant and $ym is already defined earlier in the program)
SELECT
A.in_house_supplier_cd,
B.maker_cd,
A.packing_plant_cd,
A.parts_no,
substr(A.actual_delivery_date,1,6),
A.actual_delivered_qty
FROM
TRN_DELIVERY_NO A,
TRN_PARTS B
WHERE
A.ISSUE_NO = B.ISSUE_NO
AND A.PACKING_PLANT_CD = '$packplant'
AND B.PACKING_PLANT_CD = '$packplant'
AND A.PARTS_NO = B.PARTS_NO
AND A.IN_HOUSE_SUPPLIER_CD = B.IN_HOUSE_SUPPLIER_CD
AND A.ACTUAL_DELIVERY_DATE LIKE '$ym%'
ORDER BY
in_house_supplier_cd, maker_cd, parts_no;
This sql works fine. However, what I need is that the "A.actual_delivered_qt" to be sum(A.actual_delivered_qty)... in other words, I need the sum of that particular parts and not individual quantities that were received.
When I add the "sum.." part (or even with adding a GROUP BY parts_no), the sql gives a "column ambiguously defined" error.
I believe that I've already assigned the correct table to each column and therefore would really appreciate it if someone could point out the errors as I've been stuck with this for quite a while now. Cheers!
You will need to add a GROUP BY statement, for example on parts_no, but then you will have an issue with the rest of the columns in your select statement.
For example, if you have 3 records for the same part no on different days and you are grouping by part_no and calculating the total number of items within that group number, the date no longer makes sense. The best you can do is select the max value from the date, but again, this doesn't make much sense.
You should think about what data really makes sense to include in the select statement when you are grouping by part_no and then revise the columns in the select statement to meet this new design.
When you add the group by make sure you include the table alias ( like a.parts_no ). Can you add your "new" query including the sum and group by?
Just FYI, according to PostgreSQL 9.1 Documentation - 3.5. Window Functions and Microsoft - OVER Clause (Transact-SQL) - (SQL 2008) (but they have links for MS SQL 2005
as well) GROUP BY isn't strictly needed. Just take a look at the Sample SQL queries
PostGreSQL:
SELECT depname, empno, salary, rank() OVER (PARTITION BY depname ORDER BY salary DESC) FROM empsalary;
MS SQL:
USE AdventureWorks2008R2;
GO
SELECT SalesOrderID, ProductID, OrderQty
,SUM(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Total'
,AVG(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Avg'
,COUNT(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Count'
,MIN(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Min'
,MAX(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Max'
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN(43659,43664);
GO
I've never used SQL Plus, but it looks like the OVER clause is supported there as well.

GROUP BY / aggregate function confusion in SQL

I need a bit of help straightening out something, I know it's a very easy easy question but it's something that is slightly confusing me in SQL.
This SQL query throws a 'not a GROUP BY expression' error in Oracle. I understand why, as I know that once I group by an attribute of a tuple, I can no longer access any other attribute.
SELECT *
FROM order_details
GROUP BY order_no
However this one does work
SELECT SUM(order_price)
FROM order_details
GROUP BY order_no
Just to concrete my understanding on this.... Assuming that there are multiple tuples in order_details for each order that is made, once I group the tuples according to order_no, I can still access the order_price attribute for each individual tuple in the group, but only using an aggregate function?
In other words, aggregate functions when used in the SELECT clause are able to drill down into the group to see the 'hidden' attributes, where simply using 'SELECT order_no' will throw an error?
In standard SQL (but not MySQL), when you use GROUP BY, you must list all the result columns that are not aggregates in the GROUP BY clause. So, if order_details has 6 columns, then you must list all 6 columns (by name - you can't use * in the GROUP BY or ORDER BY clauses) in the GROUP BY clause.
You can also do:
SELECT order_no, SUM(order_price)
FROM order_details
GROUP BY order_no;
That will work because all the non-aggregate columns are listed in the GROUP BY clause.
You could do something like:
SELECT order_no, order_price, MAX(order_item)
FROM order_details
GROUP BY order_no, order_price;
This query isn't really meaningful (or most probably isn't meaningful), but it will 'work'. It will list each separate order number and order price combination, and will give the maximum order item (number) associated with that price. If all the items in an order have distinct prices, you'll end up with groups of one row each. OTOH, if there are several items in the order at the same price (say £0.99 each), then it will group those together and return the maximum order item number at that price. (I'm assuming the table has a primary key on (order_no, order_item) where the first item in the order has order_item = 1, the second item is 2, etc.)
The order in which SQL is written is not the same order it is executed.
Normally, you would write SQL like this:
SELECT
FROM
JOIN
WHERE
GROUP BY
HAVING
ORDER BY
Under the hood, SQL is executed like this:
FROM
JOIN
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
Reason why you need to put all the non-aggregate columns in SELECT to the GROUP BY is the top-down behaviour in programming. You cannot call something you have not declared yet.
Read more: https://sqlbolt.com/lesson/select_queries_order_of_execution
SELECT *
FROM order_details
GROUP BY order_no
In the above query you are selecting all the columns because of that its throwing an error not group by something like..
to avoid that you have to mention all the columns whichever in select statement all columns must be in group by clause..
SELECT *
FROM order_details
GROUP BY order_no,order_details,etc
etc it means all the columns from order_details table.
To use group by clause you have to mention all the columns from select statement in to group by clause but not the column from aggregate function.
TO do this instead of group by you can use partition by clause you can use only one port to group as a partition by.
you can also make it as partition by 1
use Common table expression(CTE) to avoid this issue.
multiple CTes also come handy, pasting a case where I have used...maybe helpful
with ranked_cte1 as
( select r.mov_id,DENSE_RANK() over ( order by r.rev_stars desc )as rankked from ratings r ),
ranked_cte2 as ( select * from movie where mov_id=(select mov_id from ranked_cte1 where rankked=7 ) ) select * from ranked_cte2
select * from movie where mov_id=902

SQL query trick

I need to do
select * from xxx where name in (a,b,c...);
but I want the result set to be in the order of (a,b,c...). is this possible?
I found this question which is looks like your original question: Ordering by the order of values in a SQL IN() clause
ah - I see. you could do something horrendous with a case statement, and then order by that.. you'd effectivley be adding another column to your query to be an "order" that you could then "order by"
its ugly, but if you control the query, and the number in the 'in' clause is low, it could work (beleive an 'in' clause is limited to 255 chars)
e.g "IF name = a then 1 else if name = b then 2"
Failing that, probably best to sort in the client using a similar technique (assuming it was the client that injected the information into the 'in' clause in the first place)
-Ace
The method to do this will be DB-specific.
In Oracle, you could do something like:
SELECT * FROM xxx
where name in (a,b,c...)
ORDER BY DECODE(name,a,1,b,2,c,3);
IN statements are pretty limited, but you could get a similar effect by joining on a subquery.
here's an example:
SELECT x.*
FROM xxx as x
INNER JOIN ((select a as name, 1 as ord)
UNION
(select b as name, 2 as ord)
UNION
(select c as name, 3 as ord)) as t
ON t.name = x.name
ORDER BY t.ord
its pretty ugly, but it should work on just about any sql database. The ord field explicitly allows you to set the ordering of the result. some databases such as SqlServer support a ROWINDEX feature so you may be able to use that to clean it up a bit.