Sequence within SQL Select - sql

I'm having a bit of a problem with using my sequence within a SELECT statement.
SELECT
c.cust_name,
c.site,
customer_id_seq.nextval
FROM
customer c
WHERE
c.customer_id IS NULL
ORDER BY
c.site_code ASC
;
Is giving me an error:
00000 - "sequence number not allowed here"
*Cause: The specified sequence number (CURRVAL or NEXTVAL) is
inappropriate
here in the statement.
*Action: Remove the sequence number.
It's probably something obvious I'm doing wrong so hopefully this will be an easy answer.

You cannot use sequences in queries with ORDER BY.
Remove the ORDER BY or put in into a subquery:
SELECT q.*, customer_id_seq.nextval
FROM (
SELECT c.cust_name,
c.site
FROM customer c
WHERE c.customer_id IS NULL
ORDER BY
c.site_code ASC
) q

for IBM Imformix
In a SELECT statement, you cannot specify NEXTVAL or CURRVAL in the following contexts:
In the projection list when the DISTINCT keyword is used
In the WHERE, GROUP BY, or ORDER BY clauses
In a subquery
When the UNION operator combines SELECT statements

Why don't you use rownum instead of fetching values from sequence?

Related

Select all columns grouping by version - Postgres

I need to query all columns in a table of all customers, the main factor being the latest version for each customer.
My table:
My Query:
SELECT DISTINCT ON(code)
code,
namefile,
versioncol,
status
FROM table_A
ORDER BY versioncol desc
Error:
ERROR: SELECT DISTINCT ON expressions must match initial ORDER BY expressions
LINE 1: SELECT DISTINCT ON(code)
Postgres' error message is trying to tell you what to do:
DISTINCT ON expressions must match initial ORDER BY expressions
Actually that's quite clear: to make your code a valid DISTINCT ON query, you just need to add code (that's the DISTINCT ON expression) as a first sorting criteria to the query (ie as initial ORDER BY).
SELECT DISTINCT ON(code) a.*
FROM table_A a
ORDER BY code, versioncol DESC

Nest a select statement inside array_to_json(array_agg(row_to_json())) in PostgreSQL

I'm trying to understand why this works:
select
array_to_json(array_agg(row_to_json(positions_table)))
from (
select
sum(start_month),
function_id,
profile_id
from positions as subquery
group by function_id, profile_id
) as positions_table
But this does not:
select
profiles.id,
(array_to_json(array_agg(row_to_json(
select
sum(start_month),
function_id,
profile_id
from positions as subquery
group by function_id, profile_id
))))
from profiles
It seems like I'm not allowed to put the select... statement inside array_to_json(array_agg(row_to_json())) and that it needs to reference a table instead.
But I'm suspicious I might be missing something.
The error is syntax error near select.
You could fix your syntax error by wrapping your sub-select in brackets, but then you'd see your second error; postgres would report:
subquery must return only one column
If you fixed that error you'd see:
column "profiles.id" must appear in the GROUP BY clause or be used in an aggregate function
...which is getting closer to the real cause of your problem. Adding GROUP BY id will get postgres to report the root cause:
more than one row returned by a subquery used as an expression
The function row_to_json is expecting a single row.
To aggregate your json summaries by profile id you'll have to perform a join.
SELECT
pr.id,
array_to_json(array_agg(row_to_json(positions_table.*)))
FROM profiles pr JOIN (
SELECT sum(start_month), function_id, profile_id
FROM positions
GROUP BY function_id, profile_id
) positions_table ON positions_table.profile_id = pr.id
GROUP BY pr.id
(You can drop the .* from positions_table.*, I just added it for clarity).

"ORDER BY" in subquery - not avaliable in MonetDB?

I found that, when using order-by directly, it is ok.
SELECT t0."D" AS fd,
SUM(t0."SD") AS top
FROM "mock_table_1" AS t0
GROUP BY t0."D"
ORDER BY top ASC
LIMIT 10
but when using it in a subquery, an syntax error is reported.
SELECT * FROM (
SELECT t0."D" AS fd,
SUM(t0."SD") AS top
FROM "mock_table_1" AS t0
GROUP BY t0."D"
ORDER BY top ASC
LIMIT 10
)
here is the error message.
syntax error, unexpected ORDER, expecting UNION or EXCEPT or INTERSECT or ')' in: "select t0."A" as d0,
So, I wonder if monetdb is designed to be like this, or it is a bug?
that is the expected behavior. offset, limit, and order by are not allowed in subqueries
https://www.monetdb.org/pipermail/users-list/2013-October/006856.html
SQL-conforming DBMSes are not supposed to allow ORDER BY in subqueries, because it contradicts the conceptual model of a relational DBMS. See:
Is order by clause allowed in a subquery
for details. A way around that, however, is to use Window Functions, which MonetDB does support. Specifically, in your subquery, instead of, say,
SELECT c1 FROM t1;
you can
SELECT c1, ROW_NUMBER() OVER () as rownum from t1;
and now you have the relative order of the inner query result available to the outer query.

Why do partitions require nested selects?

I have a page to show 10 messages by each user (don't ask me why)
I have the following code:
SELECT *, row_number() over(partition by user_id) as row_num
FROM "posts"
WHERE row_num <= 10
It doesn't work.
When I do this:
SELECT *
FROM (
SELECT *, row_number() over(partition by user_id) as row_num FROM "posts") as T
WHERE row_num <= 10
It does work.
Why do I need nested query to see row_num column? Btw, in first request I actually see it in results but can't use where keyword for this column.
It seems to be the same "rule" as any query, column aliases aren't visible to the WHERE clause;
This will also fail;
SELECT id AS newid
FROM test
WHERE newid=1; -- must use "id" in WHERE clause
SQL Query like:
SELECT *
FROM table
WHERE <condition>
will execute in next order:
3.SELECT *
1.FROM table
2.WHERE <condition>
so, as Joachim Isaksson say, columns in SELECt clause are not visible in WHERE clause, because of processing order.
In your second query, column row_num are fetched in FROM clause first, so it will be visible in WHERE clause.
Here is simple list of steps in order they executes.
There is a good reason for this rule in standard SQL.
Consider the statement:
SELECT *, row_number() over (partition by user_id) as row_num
FROM "posts"
WHERE row_num <= 10 and p.type = 'xxx';
When does the p.type = 'xxx' get evaluated relative to the row number? In other words, would this return the first ten rows of "xxx"? Or would it return the "xxx"s in the first ten rows?
The designers of the SQL language recognize that this is a hard problem to resolve. Only allowing them in the select clause resolves the issue.
You can check this topic and this one on dba.stockexchange.com about order in which SQL executes SELECT clause. I think it aplies not only for PostgreSQL, but for all RDBMS.

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