Oracle issue in group by - sql

I know this question is asked by many people. But I still couldn't figure out why this is happening. Couldn't understand this logic.
I have a table mytesttable with columns id, company_name and employee_name.
I am trying to get the employee details grouping them with respect to company name. So I used the below query:
select *
from mytesttable
group by company_name;
But I get the below issue:
ORA-00979: not a GROUP BY expression
00979. 00000 - "not a GROUP BY expression"
*Cause:
*Action:
Error at Line: 28 Column: 2
Now I have tried putting count(1) in select along with my columns, tried grouping using 2 columns etc. Still the same issue. Can anyone explain me how to achieve this?
Because this is a simple group by. Logic seems to be right, but wondering why it's not fetching me the result.

Your query is:
select *
from mytesttable
group by company_name;
The * expands to all the columns. So this becomes:
select company_name, col1, col2, col3, . . . -- your question doesn't specify the column names
from mytesttable
group by company_name;
When you specify the group by, you are specifying that there is one row per company_name in the result set. The other columns are normally filled with aggregation functions, such as MIN(), SUM(), or LISTAGG().
What value should be chosen for col1? In general, SQL does not attempt to answer this question. Instead, it returns a syntax error. This is not Oracle-specific. This is the definition of the language.
What you probably want is:
select company_name, count(*) as num_employees
from mytesttable
group by company_name;

In group by clause you have to put all selected columns. As you select all but given only one column in group by as a result it thrown error, but if you simply try like this way it will work. Actually group by used for aggregated function
select company_name, count(*) from mytesttable group by company_name;

I think you mis-understand what GROUP BY does?
It doesn't put all similar records next to each other, that's ORDER BY. What GROUP BY does is to collapse all similar records in to the same row, to allow aggregate calculations like SUM() and MIN() and COUNT(), etc.
So, two examples using the same input...
id | company_name | employee_name
----+--------------+---------------
1 | zzz | aaa
2 | xxx | bbb
3 | yyy | ccc
4 | zzz | ddd
5 | xxx | eee
Using ORDER BY...
SELECT * FROM mytesttable ORDER BY company_name, employee_name
id | company_name | employee_name
----+--------------+---------------
2 | xxx | bbb
5 | xxx | eee
3 | yyy | ccc
1 | zzz | aaa
4 | zzz | ddd
Using GROUP BY...
SELECT
company_name,
COUNT(*) number_of_employees,
MAX(id) highest_id_in_company
FROM
mytesttable
GROUP BY
company_name
ORDER BY
company_name
company_name | number_of_employees | highest_id_in_company
--------------+---------------------+-----------------------
xxx | 2 | 5
yyy | 1 | 3
zzz | 2 | 4

If you use group-by expression,you have to use aggregate functions such as max,min,average,count in select statements.
For example;
select count(*),company_name,employee_name
from mytesttable
group by company_name,employee_name
order by company_name;

Related

How to have 'distinct' in having clause

EDIT: This is an example relation! I need it to work on a bigger relation so no workarounds!
So I was given a simple task and at first I didn't see what could possibly be wrong and now I just don't understand why it doesnt work.
Lets say I have a table of people and their friends and I want to select the ones who have 2 or more friends.
people
------------------------------
|person | friend | relation |
|-----------------------------
|ana | jon | friend |
|ana | jon | lover |
|ana | phillip| friend |
|ana | kiki | friend |
|mary | jannet | friend |
|mary | jannet | lover |
|peter | july | friend |
I would want to do a
SELECT person FROM people GROUP BY person HAVING count(distinct friend) > 1;
and get
-------
| ana |
-------
But I get a syntax error when using the 'distinct' in the HAVING clause.
I understand that the 'distinct' is a part of the projection clause but
how do I make 'count' only count distinct entries without an additional subquery or something?
EDIT: The best I could come up with is:
SELECT tmp.person FROM (SELECT person, count(distinct friend)
AS numfriends FROM people GROUP BY person) AS tmp
WHERE tmp.numfriends > 1;
From the doc
http://www-01.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.sqls.doc/ids_sqs_0162.htm
The condition in the HAVING clause cannot include a DISTINCT or UNIQUE
aggregate expression.
An work-around would be to have the count distinct in the select
SELECT
person,
count(distinct friend) as f_count
FROM people
GROUP BY person
HAVING f_count > 1;
UPDATE :
Checked the document and found the facts
The HAVING clause is evaluated before the SELECT - so the server
doesn't yet know about that alias.
So to achieve the goal it could be done as
select
person,
f_count
from(
SELECT
person,
count(distinct friend) as f_count
FROM people
GROUP BY person
)x
where f_count > 1
you need to write it like this
SELECT person
FROM people
WHERE relation = 'friend'
GROUP BY person
HAVING count(*) > 1;
just check this.
declare #t table(person varchar(50), Friend VARCHAR(50), relation VARCHAR(50))
INSERT INTO #T VALUES('ana', 'jon','friend')
,('ana', 'jon','lover')
,('ana', 'phillip','friend')
,('ana', 'kiki','friend')
,('mary', 'jannat','friend')
,('mary', 'jannat','lover')
SELECT DISTINCT PERSON FROM
(
SELECT person FROM #t GROUP BY person HAVING count(friend) > 1
) a
Just an alternative way via using more group by's -
select cust_xref_id
from(
select cust_xref_id,cm11
from temp_nippon_cust
group by cust_xref_id,cm11
) temp
group by cust_xref_id
having count(cm11) > 1

group by alias in Oracle

I need get all state (1,2,3,4) with out duplicates.
1 xxx
2 yyy
3 zzz
4 jjj
My first and only idea was get all state and group them:
select state1 as state,desc1 as desc from table where id=X
Union
select state2 as state,desc2 as desc from table where id=X
This get in the example 6 rows. So, to discard the duplicate I try to use a alias:
select state,desc from
(
select state1 as state,desc1 as desc from table where id=X
Union
select state2 as state,desc2 as desc from table where id=X
)
group by state;
But I got the error is not a GROUP BY expression.
I saw similar questions but I can't resolve the problem.
All the select-list items have to either be in the group by, or be aggregates. You could include both state, desc in the group-by clause, but it would be neater to use distinct instead; however, union (without all) suppresses duplicates anyway, so neither is needed here.
As Bluefeet mentioned elsewhere, desc is a keyword and has a meaning in order-by clauses, so it is not a good name for a column or alias.
This gets four rows, not six:
select state1 as state_x, desc1 as desc_x from t42 where id = 'X'
union
select state2 as state_x, desc2 as desc_x from t42 where id = 'X';
| STATE_X | DESC_X |
|---------|--------|
| 1 | xxx |
| 2 | yyy |
| 3 | zzz |
| 4 | jjj |
SQL Fiddle. It isn't clear why you think you're getting six rows, or what you are really doing differently.
The UNION should remove any duplicates. If it doesn't then you should check the data -- maybe you have extra spaces in the text columns.
Try something like this.
select state1 as state,TRIM(desc1) as desc from table where id=X
Union
select state2 as state,TRIM(desc2) as desc from table where id=X
Your first query doesn't work probably because desc1 and desc2 columns have different types e.g. char(10) and char(20). Here is an example from SQL Fiddle that shows this effect. If you change char(20) to char(10) in the left pane the query will work.

Oracle Apex Pie Chart SQL Statement

i'm not really much into SQL & Apex, but i need one statement and I would really appreciate your help on this.
The syntax of Apex pie charts is this:
SELECT link, label, value
My table looks like these simple sketch:
+------+-----------+---------+
| ID | Company | Item |
+------+-----------+---------+
| 1 | AAA |Some |
| 2 | BB |Stuff |
| 3 | BB |Not |
| 4 | CCCC |Important|
| 5 | AAA |For |
| 6 | DDDDD |Question?|
+------+-----------+---------+
I want to show the percentage of the companies.
Problem: All companies with less than 5 items should combine to one colum "other". The difficulty for me is to combine the "unimportant" companies.
Until now my statement looks like this:
SELECT null link,
company label,
COUNT(ID) value FROM table HAVING COUNT(ID) > 5 GROUP BY company
Here a wonderful diagram-sketch. :D
Thank you for your ideas!
I've not got SQL Developer in front of me but this (or a close variation) should work for you:
WITH company_count
AS (
SELECT CASE
WHEN count(*) < 5
THEN 'Other'
ELSE company
END AS company_name,
id
FROM tablename
),
company_group
AS (
SELECT company_name,
count(id) item_count
FROM company_count
GROUP BY company_name
)
SELECT NULL AS link,
company_name AS label,
item_count AS value
FROM company_group;
Hope it helps!
Okay Guys, I found the answer for my use case. Its quite similar to Ollies answer. Thanks again for the help!
WITH sq1 AS (SELECT company, COUNT (*) AS count FROM
(SELECT CASE WHEN COUNT (*) OVER (Partition By company) > 5 THEN company
ELSE 'other' END AS company, id FROM table) GROUP BY company)
SELECT null link, company label, count value FROM sq1 ORDER BY count desc

SQL sum field when column values match

The title was hard to word but the question is pretty simple. I searched all over here and could not find something for my specific issue so here it is. I'm usuing Microsoft SQL Server Management Studio 2010.
Table Currently looks like this
| Value | Product Name|
| 300 | Bike |
| 400 | Bike |
| 300 | Car |
| 300 | Car |
I need the table to show me the sum of Values where Product Name matches - like this
| TOTAL | ProductName |
| 700 | Bike |
| 600 | Car |
I've tried a simple
SELECT
SUM(Value) AS 'Total'
,ProductName
FROM TableX
But the above doesn't work. I end up getting the sum of all values in the column. How can I sum based on the product name matching?
Thanks!
SELECT SUM(Value) AS 'Total', [Product Name]
FROM TableX
GROUP BY [Product Name]
SQL Fiddle Example
Anytime you use an aggregate function, (SUM, MIN, MAX ... ) with a column in the SELECT statement, you must use GROUP BY. This is a group function that indicates which column to group the aggregate by. Further, any columns that are not in the aggregate cannot be in your SELECT statement.
For example, the following syntax is invalid because you are specifying columns (col2) which are not in your GROUP BY (even though MySQL allows for this):
SELECT col1, col2, SUM(col3)
FROM table
GROUP BY col1
The solution to your question would be:
SELECT ProductName, SUM(Value) AS 'Total'
FROM TableX
GROUP BY ProductName

Accessing column alias in postgresql

Having a little bit of trouble understanding how a query alias works in postgresql.
I have the following:
SELECT DISTINCT robber.robberid,
nickname,
Count(accomplices.robberid) AS count1
FROM robber
INNER JOIN accomplices
ON accomplices.robberid = robber.robberid
GROUP BY robber.robberid,
robber.nickname
ORDER BY Count(accomplices.robberid) DESC;
robberid | nickname | count1
----------+--------------------------------+--------
14 | Boo Boo Hoff | 7
15 | King Solomon | 7
16 | Bugsy Siegel | 7
23 | Sonny Genovese | 6
1 | Al Capone | 5
...
I can rename the "count1" column using the as command but I can't seem to be able to refer to this again in the query? I am trying to include a HAVING command at the end of this query to query only objects who have a count less than half of the max.
This is homework but I am not asking for the answer only a pointer to how I can include the count1 column in another clause.
Can anyone help?
In general, you can't refer to an aggregate column's alias later in the query, and you have to repeat the aggregate
If you really want to use its name, you could wrap your query as a subquery
SELECT *
FROM
(
SELECT DISTINCT robber.robberid, nickname, count(accomplices.robberid)
AS count1 FROM robber
INNER JOIN accomplices
ON accomplices.robberid = robber.robberid
GROUP BY robber.robberid, robber.nickname
) v
ORDER BY count1 desc