How to GROUP BY on Oracle? - sql

I need help with sql oracle, my group by doesnt work and i'm working on a shell so i don't have any help.
Can someone tell me how to group this next request by noArticle.
SELECT Article.noArticle, quantite
FROM Article LEFT JOIN LigneCommande ON Article.noArticle = LigneCommande.noArticle
GROUP BY Article.noArticle
/
Thank you

To tie things up, this is the correct SQL.
SELECT Article.noArticle, sum(quantite)
FROM Article LEFT JOIN LigneCommande ON Article.noArticle = LigneCommande.noArticle
GROUP BY Article.noArticle

You are grouping by a column and then you attempt to use the quantite field which is not group-level, it is record-level. Group by is aggregation and you have to use aggregate columns (the columns you are grouping by or aggregate functions on columns, like sum, avg, count, max or min). You need to aggregate your record-level fields to be able to use them in your projection (select clause). To name an example, your attempt was like trying to get the hair color of American women (of course, there are many American women and they might have different hair color, so it is unnatural and un-wise to attempt to get the value of hair color from the set of American women). Your fixed query is as follows:
SELECT Article.noArticle, sum(quantite)
FROM Article LEFT JOIN LigneCommande ON Article.noArticle = LigneCommande.noArticle
GROUP BY Article.noArticle

For my situation i need the summation of the quantite so in order to make it work i added SUM(quantite) and then i grouped by noArticle

Related

convert access group by query to sql server query

I'm unable to convert MS Access query to SQL SERVER Query, with changing the group by columns because it will effect in the final result. The purpose of this query is to calculate the Creditor and debtor of accounts of projects.
I tried rewriting with 'CTE' but couldn't get any good result.. I hope someone could help me.. Thanks in advance...
this is the query I want to convert:
SELECT Sum(ZABC.M) AS M, Sum(ZABC.D) AS D, ZABC.ACC_NUMBER, ZABC.PROJECT_NUMBER, [M]-[D] AS RM, [D]-
[M] AS RD
FROM ZABC
GROUP BY ZABC.ACC_NUMBER, ZABC.PROJECT_NUMBER
ORDER BY ZABC.PROJECT_NUMBER;
The problem with the query are [M] and [D] in the select clause: these columns should either be repeated in the group by clause, or surrounded by an aggregate function. Your current group by clause gives you one row per (acc_number, project_number) tuple: you need to choose which computation you want for D and M, that may have several different values per group.
You did not explain the purpose of the original query. Maybe you meant:
SELECT
Sum(ZABC.M) AS M,
Sum(ZABC.D) AS D,
ZABC.ACC_NUMBER,
ZABC.PROJECT_NUMBER,
Sum(ZABC.M) - SUM(ZABC.D) AS RM,
SUM(ZABC.D) - SUM(ZABC.M) AS RD
FROM ZABC
GROUP BY ZABC.ACC_NUMBER, ZABC.PROJECT_NUMBER
ORDER BY ZABC.PROJECT_NUMBER;
There is a vast variety of aggregate functions available for you to pick from, such as MIN(), MAX(), AVG(), and so on.

Subtotal levels for ROLLUP on four columns in Oracle SQL

I'm trying to construct an Oracle SQL query using the ROLLUP operator. The query needs to summarize sales by year, quarter, store state, and store city over two years, with the result including subtotals for the two hierarchical dimensions of year/quarter and state/city. Here's my attempt thus far:
SELECT storestate, storecity, calyear, calquarter, SUM(sales) AS Sales
FROM store_dim, time_dim, sales_fact
WHERE sales_fact.storeid = store_dim.storeid
AND sales_fact.timenum = time_dim.timenum
AND (calyear BETWEEN 2011 AND 2012)
GROUP BY ROLLUP(calyear, calquarter, storestate, storecity);
I'm trying to figure out if, as it's currently written, the query is showing subtotals for the two hierarchies I'm looking for, rather than treating them as one big one. Attempting to map out the subtotal levels by hand didn't help, and I haven't been able to find any examples of a single ROLLUP with four columns from two dimensions, or an example of two ROLLUP operators in a single GROUP BY clause, like below:
GROUP BY ROLLUP(calyear, cal quarter), ROLLUP(storestate, storecity)
A breakdown of the subtotal levels produced by the two GROUP BY clauses would be hugely helpful.
Edit: I'm specifically to use ROLLUP here. GROUPING SETS would generally be the first choice for this kind of query otherwise.
Use grouping sets . . . and proper, explicit, standard join syntax:
select s.storestate, s.storecity, t.calyear, t.calquarter,
sum(sf.sales) AS Sales
from sales_fact sf join
store_dim s
on s.storeid = sf.storeid join
time_dim t
on sf.timenum = t.timenum
where calyear between 2011 and 2012
group by grouping sets ( (calyear, calquarter, storestate, storecity),
(calyear, calquarter), (storestate, storecity)
);

Query using COUNT returns records where the count is positive only

Good day everyone.
Consider this portion of a relational SQLite database:
floors(number) - rooms(number, #floorNumber)
I aim to query for the number of rooms per floor. This is my attempt:
select floors.number, count(rooms.floornumber)
from floors, rooms where floors.number=rooms.floornumber
group by floors.number, rooms.floornumber;
Example:
1|5
2|7
3|5
4|3
The issue is that I also would like the query to return records where the floor contains 0 rooms (for example floor number 5 exists in the "floors" table but isn't shown in the query result).
Your assistance is appreciated. Thank you.
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
You need a LEFT JOIN, but you cannot even see what you need because of the way that your query is written.
select f.number, count(r.floornumber)
from floors f left join
rooms r
on f.number = r.floornumber
group by f.number;

SQL Work out average from joined column

I have 3 columns I need to display and I need to join on another column that calculates the AVG from the CLUB_FEE column. My code does not work, it throws a "not a single-group group function" Can someone please help? Here is my SQL:
SELECT S.MEMBER_ID, S.CLUB_ID, C.CLUB_FEE, AVG(C.CLUB_FEE) AVGINCOME
FROM SUBSCRIPTION S, CLUB C
WHERE S.CLUB_ID = C.CLUB_ID;
i Suggest to use Inner join try it also When you include an aggregate function (like avg, sum) in your query, you must group by all columns :
SELECT S.MEMBER_ID, S.CLUB_ID, C.CLUB_FEE, AVG(C.CLUB_FEE) as AVGINCOME
FROM SUBSCRIPTION S INNER JOIN CLUB C
ON S.CLUB_ID = C.CLUB_ID
GROUP BY
S.MEMBER_ID, S.CLUB_ID, C.CLUB_FEE ;
Learn to use explicit JOIN syntax. Simple rule: Never use commas in the FROM clause. Always use explicit JOIN syntax.
In your case, you need to remove columns from the SELECT and the GROUP BY. If you want the average fee paid by any member, then you don't need the GROUP BY at all:
SELECT AVG(C.CLUB_FEE) as AVGINCOME
FROM SUBSCRIPTION S JOIN
CLUB C
ON S.CLUB_ID = C.CLUB_ID;
If you want to control the formatting, either use to_char():
SELECT TO_CHAR(AVG(C.CLUB_FEE), '999.99') as AVGINCOME
(check the documentation for other formats).
Or, cast to a decimal:
SELECT CAST(AVG(C.CLUB_FEE) AS DECIMAL(10, 2)) as AVGINCOME
If you need to display the three columns and the average, not just the average alone, you can do something like this:
SELECT S.MEMBER_ID, S.CLUB_ID, C.CLUB_FEE, A.AVGINCOME
FROM SUBSCRIPTION S INNER JOIN CLUB C
ON S.CLUB_ID = C.CLUB_ID
CROSS JOIN (SELECT AVG(CLUB_FEE) AS AVGINCOME FROM CLUB) A
;
If you need the average rounded to two decimal places, use ROUND(AVG(CLUB_FEE), 2) in the subquery.
A fancier solution, which doesn't require a join (so it doesn't scan the CLUB table twice), uses AVG as an analytic function - but doesn't partition by anything. You still need the PARTITION BY clause (with an empty column list) to indicate it's used as an analytic function, not as an aggregate.
SELECT S.MEMBER_ID, S.CLUB_ID, C.CLUB_FEE,
ROUND(AVG(C.CLUB_FEE) OVER (PARTITION BY NULL)) AS AVGINCOME
FROM SUBSCRIPTION S INNER JOIN CLUB C
ON S.CLUB_ID = C.CLUB_ID
;
Even fancier (although functionally identical) - the keyword OVER is needed to indicate analytic function, but you can also write it as OVER() (no need to even mention PARTITION BY NULL).

Subqueries and AVG() on a subtraction

Working on a query to return the average time from when an employee begins his/her shift and then arrives at the first home (this DB assumes they are salesmen).
What I have:
SELECT l.OFFICE_NAME, crew.EMPLOYEE_NAME, //avg(first arrival time)
FROM LOCAL_OFFICE l, CREW_WORK_SCHEDULE crew,
WHERE l.LOCAL_OFFICE_ID = crew1.LOCAL_OFFICE_ID
You can see the AVG() command is commented out, because I know the time that they arrive at work, and the time they get to the first house, and can find the value using this:
(SELECT MIN(c.ARRIVE)
FROM ORDER_STATUS c
WHERE c.USER_ID = crew.CREW_ID)
-(SELECT START_TIME
FROM CREW_SHIFT_CODES
WHERE WORK_SHIFT_CODE = crew.WORK_SHIFT_CODE)
Would the best way be to simply put the above into the the AVG() parentheses? Just trying to learn the best methods to create queries. If you want more info on any of the tables, etc. just ask, but hopefully they're all named so you know what they're returning.
As per my comment, the example you gave would only return one record to the AVG function, and so not do very much.
If the sub-query was returning multiple records, however, your suggestion of placing the sub-query inside the AVG() would work...
SELECT
AVG((SELECT MIN(sub.val) FROM sub WHERE sub.id = main.id GROUP BY sub.group))
FROM
main
GROUP BY
main.group
(Averaging a set of minima, and so requiring two levels of GROUP BY.)
In many cases this gives good performance, and is maintainable. But sometimes the sub-query grows large, and it can be better to reformat it using an inline view...
SELECT
main.group,
AVG(sub_query.val)
FROM
main
INNER JOIN
(
SELECT
sub.id,
sub.group,
MIN(sub.val) AS val
FROM
sub
GROUP BY
sub.id
sub.group
)
AS sub_query
ON sub_query.id = main.id
GROUP BY
main.group
Note: Although this looks as though the inline view will calculate a lod of values that are not needed (and so be inefficient), most RDBMS optimise this so only the required records get processes. (The optimiser knows how the inner query is being used by the outer query, and builds the execution plan accordingly.)
Don't think of subqueries: they're often quite slow. In effect, they are row by row (RBAR) operations rather than set based
join all the table together
I've used a derived table to calculate the 1st arrival time
Aggregate
Soemthing like
SELECT
l.OFFICE_NAME, crew.EMPLOYEE_NAME,
AVG(os.minARRIVE - cs.START_TIME)
FROM
LOCAL_OFFICE l
JOIN
CREW_WORK_SCHEDULE crew On l.LOCAL_OFFICE_ID = crew1.LOCAL_OFFICE_ID
JOIN
CREW_SHIFT_CODES cs ON cs.WORK_SHIFT_CODE = crew.WORK_SHIFT_CODE
JOIN
(SELECT MIN(ARRIVE) AS minARRIVE, USER_ID
FROM ORDER_STATUS
GROUP BY USER_ID
) os ON oc.USER_ID = crew.CREW_ID
GROUP B
l.OFFICE_NAME, crew.EMPLOYEE_NAME
This probably won't give correct data because of the minARRIVE grouping: there isn't enough info from ORDER_STATUS to show "which day" or "which shift". It's simply "first arrival for that user for all time"
Edit:
This will give you average minutes
You can add this back to minARRIVE using DATEADD, or change to hh:mm with some %60 (modul0) and /60 (integer divide
AVG(
DATEDIFF(minute, os.minARRIVE, os.minARRIVE)
)