I am trying to convert a subquery with a complex query from Oracle to Postgres. Below is the subquery and the error it gives. I know 'WITHIN GROUP' is also there in Postgres. What am I missing? I even changed Listagg to String_agg but get the same error.
Select a, Listagg(b, ', ') WITHIN GROUP (ORDER BY b) "a"
from table;
Errors:
ERROR: syntax error at or near "WITHIN" LINE 65: ...a, Listagg(b, ', ') WITHIN GRO...
********** Error **********
ERROR: syntax error at or near "WITHIN" SQL state: 42601 Character: 5290
Always use the keyword AS for column aliases in Postgres.
No need to double quote lower case identifiers. (Unlike Oracle, Postgres lower-cases identifiers unless double quoted.)
This also means, you end up with two columns names a, So you have to use "A" for the first one or something - not sure if your column name is "A" or a.
WITHIN GROUP can only be used for these Ordered-Set Aggregate Functions or these Hypothetical-Set Aggregate Functions in Postgres 9.4 or later. string_agg() is currently not among them. But you can use almost any aggregate function as window function ("analytic function" in Oracle terminology).
Either way, your query does not seem valid in either RDBMS. You have an aggregate function and an un-aggregated column, but no GROUP BY clause. Either you want that to be a window function (analytic function in Oracle), then the OVER clause is missing. Or you need to add GROUP BY a for an aggregate function.
I guess you want something like:
SELECT a, string_agg(b, ', ' ORDER BY b) AS a2 -- column names?
FROM tbl
GROUP BY a;
Postgres allows to add ORDER BY to any aggregate function. (Only makes sense for some.)
For a simple query like this, you can also just sort in a subquery:
SELECT a, string_agg(b, ', ') AS a
FROM (SELECT a, b FROM tbl ORDER BY a,b) t
GROUP BY a;
Which is typically faster. But read the manual here.
Related
As we all know, the ORDER BY clause is processed after the SELECT clause, so a column alias in the SELECT clause can be used.
However, I find that I can’t use the aliased column in a calculation in the ORDER BY clause.
WITH data AS(
SELECT *
FROM (VALUES
('apple'),
('banana'),
('cherry'),
('date')
) AS x(item)
)
SELECT item AS s
FROM data
-- ORDER BY s; -- OK
-- ORDER BY item + ''; -- OK
ORDER BY s + ''; -- Fails
I know there are alternative ways of doing this particular query, and I know that this is a trivial calculation, but I’m interested in why the column alias doesn’t work when in a calculation.
I have tested in PostgreSQL, MariaDB, SQLite and Oracle, and it works as expected. SQL Server appears to be the odd one out.
The documentation clearly states that:
The column names referenced in the ORDER BY clause must correspond to
either a column or column alias in the select list or to a column
defined in a table specified in the FROM clause without any
ambiguities. If the ORDER BY clause references a column alias from
the select list, the column alias must be used standalone, and not as
a part of some expression in ORDER BY clause:
Technically speaking, your query should work since order by clause is logically evaluated after select clause and it should have access to all expressions declared in select clause. But without looking at having access to the SQL specs I cannot comment whether it is a limitation of SQL Server or the other RDBMS implementing it as a bonus feature.
Anyway, you can use CROSS APPLY as a trick.... it is part of FROM clause so the expressions should be available in all subsequent clauses:
SELECT item
FROM t
CROSS APPLY (SELECT item + '') AS CA(item_for_sort)
ORDER BY item_for_sort
It is simply due to the way expressions are evaluated. A more illustrative example:
;WITH data AS
(
SELECT * FROM (VALUES('apple'),('banana')) AS sq(item)
)
SELECT item AS s
FROM data
ORDER BY CASE WHEN 1 = 1 THEN s END;
This returns the same Invalid column name error. The CASE expression (and the concatenation of s + '' in the simpler case) is evaluated before the alias in the select list is resolved.
One workaround for your simpler case is to append the empty string in the select list:
SELECT
item + '' AS s
...
ORDER BY s;
There are more complex ways, like using a derived table or CTE:
;WITH data AS
(
SELECT * FROM (VALUES('apple'),('banana') AS sq(item)
),
step2 AS
(
SELECT item AS s FROM data
)
SELECT s FROM step2 ORDER BY s+'';
This is just the way that SQL Server works, and I think you could say "well SQL Server is bad because of this" but SQL Server could also say "what the heck is this use case?" :-)
I am using this query to get the aggregated results:
select _bs, string_agg(_wbns, ',') from bag group by 1;
I am getting this error:
Error running query: function string_agg(character varying, "unknown")
does not exist HINT: No function matches the given name and argument
types. You may need to add explicit type casts.
I also tried array_agg() and getting the same error.
Please help me in figuring out the other options I can use to aggregate the results.
you have to use listagg for reshift
For each group in a query, the LISTAGG aggregate function orders the rows for that group according to the ORDER BY expression, then concatenates the values into a single string.
LISTAGG is a compute-node only function. The function returns an error if the query doesn't reference a user-defined table or Amazon Redshift system table.
Your query will be as like below
select _bs,
listagg(_wbns,',')
within group (order by _wbns) as val
from bag
group by _bs
order by _bs;
for better understanding Listagg
Redshift has a listagg function you can use instead:
SELECT _bs, LISTAGG(_wbns, ',') FROM bag GROUP BY _bs;
To get an array type back instead of a varchar, you need to combine the LISTAGG function with the SPLIT_TO_ARRAY function like so:
SELECT
some_grouping_key,
SPLIT_TO_ARRAY(LISTAGG(col_to_agg, ','), ',')
FROM some_table
GROUP BY 1
Use listagg function:
select _bs,
listagg(_wbns,',')
within group (order by _bs) as val
from bag
group by _bs
Got Error:One or more of the used functions must be applied on at least one user created tables.
Examples of user table only functions are LISTAGG, MEDIAN, PERCENTILE_CONT, etc
SELECT refc.constraint_name, refc.update_rule, refc.delete_rule, kcu.table_name,
LISTAGG(distinct kcu.column_name, ',') AS columns
FROM information_schema.referential_constraints AS refc,
information_schema.key_column_usage AS kcu
WHERE refc.constraint_schema = 'abc' AND refc.constraint_name = kcu.constraint_name AND refc.constraint_schema = kcu.table_schema
AND kcu.table_name = 'xyz'
GROUP BY refc.constraint_name, refc.update_rule, refc.delete_rule, kcu.table_name;
I am trying to select specific values from a column in JSL, but there is an issue. The column name is:
Sum(ow_blah)
And I would like to: select where(Sum(ow_blah) == 0)
Unfortunately, the combination of the keyword Sum and parentheses have led to significant problems. And Aliasing is not allowed in select statements. How can I use the Sum function within a where clause?
Use HAVING after grouping, as in:
select id, sum(ow_blah)
from my_table
group by id
having sum(ow_blah) = 0
Since "sum" is a keyword, you need to explicitly let JMP know that you are selecting a column by the name Sum(ow_blah). So for that, use it as:
Column("Sum(Ow_blah)")
When I use the following sql command for Oracle:
SELECT CATEGORY,ANTIGENNAME,LATINCOMPOSITION,HYCORCODE,FDACLEARANCE, LISTAGG(ORCHARDCODE, ';')
WITHIN GROUP (ORDER BY ORCHARDCODE) as code
from tablename
group by HYCORCODE
I'm seem to be getting a ORA-00923 error:
ORA-00923: FROM keyword not found where expected
What could be causing the error to show up?
LISTAGG is not available in your version of Oracle. Check your version with this statement:
select * from v$version;
LISTAGG is only available on versions >= 11.2.x
From "Oracle Database 11g Release 2 (11.2) New Features in Data Warehousing":
Analytic Functions
New SQL analytic functions have been introduced that enable you to list (or concatenate) measure values within a group (LISTAGG).
code is not a reserved word, so I don't think it needs to be quoted (see here).
However, you have an aggregation function, so you need the correct columns in the group by:
SELECT CATEGORY, ANTIGENNAME, LATINCOMPOSITION, HYCORCODE, FDACLEARANCE,
LISTAGG(ORCHARDCODE, ';') WITHIN GROUP (ORDER BY ORCHARDCODE) as code
from tablename
group by CATEGORY, ANTIGENNAME, LATINCOMPOSITION, HYCORCODE, FDACLEARANCE;
This definitely fixes a problem with your query. I'm not sure if it will fix your particular error. When I leave out columns from the group by, I get "ORA-00979 (not a GROUP BY expression)."
I want to assign the result of count to a variable, so I can use it later in the query, here is my code:
select distinct(Artist), count(distinct(Instrument)) as allins
from performers
where allins = (select count(distinct(x.Instrument))
from performers x)
group by Artist;
the error: ORA-00904: "ALLINS": invalid identifier
This is your query:
select distinct(Artist), count(distinct(Instrument)) as allins
from performers
where allins = (select count(distinct(x.Instrument)) from performers x)
group by Artist;
Naughty, naughty. You cannot use a column alias defined in the select in a where clause. You also can't use aggregation function in the where clause, so the code doesn't make sense. What you want is a having clause:
select Artist, count(distinct(Instrument)) as allins
from performers
group by Artist
having count(distinct Instrument) = (select count(distinct x.Instrument) from performers x)
Note: you almost never need select distinct when you have an aggregation query. And, distinct isn't a function so parenthesis are unnecessary.
Standard SQL disallows references to column aliases in a WHERE clause.
This restriction is imposed because when the WHERE clause is evaluated, the column value may not yet have been determined.
Column_alias can be used in an ORDER BY clause, but it cannot be used in a WHERE, GROUP BY, or HAVING clause.
Documentation references:
http://dev.mysql.com/doc/refman/5.5/en/problems-with-alias.html
http://msdn.microsoft.com/en-us/library/ms173451.aspx
The execution for SQL is definitely not the same as Java or C, so often it trips up new programmers getting into the language.
More often than not, the database's order for understanding SQL instructions goes like this:
FROM -> WHERE -> GROUP BY -> ... -> SELECT
In order to do this properly you can't state that something is an alias in the SELECT clause, and expect it to work, because the program would most likely start from the FROM clause.
Also, from my experience, column aliases don't work with each other nicely when referencing each other in the SELECT clause.
My rather unfortunate solution would be to just not use aliases and type the whole thing out.
Also, you absolutely, positively, should not use an aggregate function in the WHERE clause. It must always be in the HAVING clause. You also need to use a GROUP BY clause if you don't want Oracle to complain about asking for the Artist. Also, since you are grouping by the Artist and the other function is an aggregate, you don't need to use DISTINCT.