What is missing (if anything) from this SQL statement? [duplicate] - sql

This question already has an answer here:
Mysql : Aggregation function is not working without group by
(1 answer)
Closed 1 year ago.
SELECT EXTRACT(YEAR FROM created_at) AS yr, count(*) AS users_count
FROM users;
I'm new to SQL (so new that I can't find anything wrong with this). There may not be, and it may be a trick question. Would appreciate feedback!

You should use "Group BY" function too, because you use COUNT function with an another column.
For example:
SELECT EXTRACT(YEAR FROM created_at) AS yr, count(*) AS users_count FROM users group by YR;

Related

Count over previously defined alias [duplicate]

This question already has answers here:
Why can't I use column aliases in the next SELECT expression?
(4 answers)
Closed 3 months ago.
I'm trying to avoid writing twice the EXTRACT condition. There is any way to do that? Count over the previous alias apparently is not valid.
SELECT EXTRACT(DECADE FROM to_date(released_year::text, 'yyyy')) AS decade,
count(decade) AS total_by_decade
FROM album ...
Basically you can avoit it completely, but you can make a CTE
WITH
CTE as(
SELECT EXTRACT(DECADE FROM to_date(released_year::text, 'yyyy')) AS decade
FROM album ...)
SELECT decade, count(decade) AS total_by_decade FROM CTe GROUP BY decade

SQL : How can I get previous day [duplicate]

This question already has answers here:
Is there a way to access the "previous row" value in a SELECT statement?
(9 answers)
Closed 8 months ago.
How can I get the result in the PreviousDay column that the day should be -1 from the day in efdt column for all rows?
If the efdt date is 2001-04-02 the result in PreviousDay should be 2001-04-01 and DATEDIFF is 334
Image attached with it please refer it.
You can use the SQL Server LEAD window function over the "efdt" field, which will take the following value given two clauses:
PARTITION BY, which indicates the groups to work on
ORDER BY, which decided which value to take according to an order imposed by one (or more) of your fields.
SELECT T.*,
DATEDIFF(DAY, efdt, PreviousDay)
FROM (SELECT T1.*,
LEAD(efdt) OVER(PARTITION BY emcd ORDER BY efdt) AS PreviousDay
FROM psf206 T1) AS T
ORDER BY emcd, efdt
Check the demo here.
Note: if you want one day less for each row, just add -1 after the DATEDIFF operation (demo).

Column alias is not recognized [duplicate]

This question already has answers here:
Referring to a select aggregate column alias in the having clause in Postgres
(2 answers)
Closed 2 years ago.
This minimal example is supposed to extract year from time stamps, then count something in a given year.
SELECT EXTRACT(YEAR FROM rental_ts) as year,
COUNT(DISTINCT rental_id)
FROM rental
GROUP BY year
HAVING year=2020
Running it, I get an error column "year" does not exist. What is the reason for this?
Code with explicit HAVING EXTRACT(YEAR FROM rental_ts)=2020 works without problems, but not very convenient.
Same would happen if I use year in WHERE clause instead.
I practice in this playground. It uses PostgreSQL.
Alas, that is true. Column aliases are not allowed. One solution is to repeat the expression:
SELECT EXTRACT(YEAR FROM rental_ts) as year,
COUNT(DISTINCT rental_id)
FROM rental
GROUP BY year
HAVING EXTRACT(YEAR FROM rental_ts) = 2020;
A better solution is to filter before aggregating:
SELECT EXTRACT(YEAR FROM rental_ts) as year,
COUNT(DISTINCT rental_id)
FROM rental
WHERE rental_ts >= '2020-01-01' AND rental_ts < '2021-01-01'
GROUP BY year;
This is better for two reasons. First, it is index (and partition) compatible. Second, it reduces the amount of data needed for the aggregation.

How to fix "Inner Join Group-By" question [duplicate]

This question already has answers here:
ORA-00979 not a group by expression
(10 answers)
Closed 3 years ago.
Trying to run a query to pull back no duplicate lines. Currently when running this script I get an error back from Oracle saying
"ORA-00979: not a GROUP BY expression"
Tried removing different select rows.
SELECT QUEUE_NAME, ITEMS_IN_QUEUE, CREATION_USR_ID
FROM IN_WF_QUEUE B
INNER JOIN IN_WF_ITEM A
ON A.QUEUE_ID = B.QUEUE_ID
AND B.QUEUE_NAME LIKE '__________ %'
AND (A.QUEUE_START_TIME < (select sysdate from DUAL)-1000)
GROUP BY B.QUEUE_ID;
Thank you in advance for any help on this issue.
If you want to remove duplicates, why don't you use DISTINCT? That's more natural than using GROUP BY without any aggregates.
SELECT DISTINCT
queue_name, items_in_queue, creation_usr_id
FROM in_wf_queue b
INNER JOIN in_wf_item A
ON A.queue_id = b.queue_id
AND b.queue_name LIKE '__________ %'
AND A.queue_start_time < sysdate - 1000;
Also, there's no need to select SYSDATE from dual; it is a function that can be used standalone, as in my example. Note that it returns both date and time, so - maybe you'd want to remove time component by truncating it, i.e. use trunc(sysdate). Subtracting 1000 from it means "1000 days ago"; just saying, to avoid possible confusion.

Oracle concatenation of columns with comma [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I combine multiple rows into a comma-delimited list in Oracle?
Could some one please tell me how to achieve the following?
Table:
efforts_id cycle_name release_name
123 quarter march
123 half april
123 full april
124 quarter may
My expected output:
efforts_id cycle_name release_name
123 quarter,half,full march,april
124 quarter may
I am a beginner in oracle so not sure how to do this. Any help would be appreciated.
Thanks
What you need is "string aggregation". Tim Hall's excellent site shows the alternatives you have depending on the exact version of Oracle you have: http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php
In 11gR2 (current at time of writing), you should use the listagg function:
select
efforts_id,
listagg(cycle_name, ',') within group (order by cycle_name) as cycle_name,
listagg(release_name, ',') within group (order by release_name) as release_name
from my_table
group by efforts_id;
Note that the use of the wm_concat function is unsupported by Oracle...
You will want to use LISTAGG() to perform this task. The other answers don't remove any of the duplicate values, to remove the duplicates, you can use something similar to this:
select c.efforts_id,
c.cycle_name,
listagg(r.release_name, ', ') within group (order by c.efforts_id) as release_name
from
(
select efforts_id,
listagg(cycle_name, ', ') within group (order by efforts_id) as cycle_name
from yourtable
group by efforts_id
) c
inner join
(
select distinct efforts_id, release_name
from yourtable
) r
on c.efforts_id = r.efforts_id
group by c.efforts_id, c.cycle_name
See SQL Fiddle with Demo
If you have Oracle 11g R2, then LISTAGG is the preferred way to do it:
SELECT efforts_id,
LISTAGG(cycle_name) WITHIN GROUP(ORDER BY cycle_name),
LISTAGG(release_name) WITHIN GROUP(ORDER BY cycle_name)
FROM MY_TABLE
GROUP BY efforts_id
If not, this article shows the alternative ways of doing it.
Through the WM_concat function (and GROUP BY of course)
SELECT efforts_id, wm_concat(cycle_name), wm_concat(release_name)
FROM MY_TABLE
GROUP BY efforts_id
Hmmm, just found this:
Note that WM_CONCAT is undocumented and unsupported by Oracle, meaning it should not be used in production systems
The LISTAGG function, which can produce the same output as WM_CONCAT is both documented and supported by Oracle.