group by alias in Oracle - sql

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.

Related

How to add a total row at the end of the table in t-sql?

I need to add a row of sums as the last row of the table. For example:
book_name | some_row1 | some_row2 | sum
---------------+---------------+---------------+----------
book1 | some_data11 | some_data12 | 100
book2 | some_data21 | some_data22 | 300
book3 | some_data31 | some_data32 | 500
total_books=3 | NULL | NULL | 900
How can I do this? (T-SQL)
You can use union all :
select book_name, some_row1, some_row2, sum
from table t
union all
select cast(count(*) as varchar(255)), null, null, sum(sum)
from table t;
However, count(*) will give you no of rows available in table, if the book_name has null value also, then you need count(book_name) instead of count(*).
Try with ROLLUP
SELECT CASE
WHEN (GROUPING([book_name]) = 1) THEN 'total_books'
ELSE [book_name] END AS [book_name],some_row1, some_row2
,SUM(]sum]) as Total_Sales
From Before
GROUP BY
[book_name] WITH ROLLUP
I find that grouping sets is much more flexible than rollup. I would write this as:
select coalesce(book_name,
replace('total_books=#x', '#x', count(*))
) as book_name,
col2, col3, sum(whatever)
from t
group by grouping sets ( (book_name), () );
Strictly speaking, the GROUPING function with a CASE is better than COALESCE(). However, NULL values on the grouping keys is quite rare.

Oracle issue in group by

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;

Return only first row with particular value in a column

I realize that this has probably been asked a billion times, and I could swear I've done this in the past, but tonight I've got brain block or something and can't figure it out...
I have a database table ("t1") where I need to be able to retrieve only the first row where a particular value appears in a particular column.
Here's a sample of the data:
id | qID | Name
---------------------
1 | 1 | Bob
2 | 3 | Fred
3 | 1 | George
4 | 1 | Jack
What I want as a result is:
id | qID | Name
---------------------
1 | 1 | Bob
2 | 3 | Fred
The only column I actually need to get out of the query is the first one, but that's not where the duplicates need to be eliminated, and I thought it might be confusing not to show the entire row.
I've tried using this:
select id, qID, ROW_NUMBER() over(partition by qID order by qID) as zxy
from t1 where zxy = 1
But it gives me this error:
Msg 207, Level 16, State 1, Line 14
Invalid column name 'zxy'.
If I remove the where part of the query, the rest of it works fine. I've tried different variable names, using single or double quotes around 'zxy' but it seems to make no difference. And try as I might, I can't find the part of the SQL Server documentation where it discusses assigning a variable name to an expression, as in the "as zxy" part of the above query... if anybody has a link for that, that's quite useful.
Needless to say, I've tried other variable names besides "zxy" but that makes no difference.
Help!
WHERE clause is applied earlier in the process than SELECT. Therefore the calculated column zxy is not available in WHERE. In order to achieve your goal you need to put your original query in a subquery or CTE.
select id, qid
from
(
select id, qID, ROW_NUMBER() over(partition by qID order by qID) as zxy
from t1
) q
where zxy = 1
Output:
| id | qid |
|----|-----|
| 1 | 1 |
| 2 | 3 |
Here is SQLFiddle demo
Logical Processing Order of the SELECT statement
1 FROM
2 ON
3 JOIN
4 WHERE
5 GROUP BY
6 WITH CUBE or WITH ROLLUP
7 HAVING
8 SELECT
9 DISTINCT
10 ORDER BY
11 TOP
Where Clause Execute Before Select Clause so You can not find ZXY in Where cluase
with cte as
(
select id, qID, ROW_NUMBER() over(partition by qID order by qID) as zxy
from t1
)
select * from cte where zxy = 1
Here is my blog it might help you http://sqlearth.blogspot.in/2015/05/how-sql-select-statement-logically-works.html

Displaying records in the custom sequence

I want to fetch data from the database in my custom sequence.
For example if the query is;
SQL>Select * from table1 where id in(5,3,4)
So expected result would be.
Id | Name
----------
5 | John
3 | David
4 | Rock
but data is displaying in following order:
Id | Name
----------
3 | David
4 | Rock
5 | John
Can anyone help me to achieve this result?
The where clause is not relevant to the order of the results.
You can use "order by XXX" to arrange results by specific column/s,
but as I can see in your example it is not ordered by id or name.
So... I would suggest to add another column named "position" or "pos" and it will contain an integer with the desired order, than simple query with order by that column.
select *
from table1
where id in(5,3,4)
order by position
check this, it will give your wanted order
Select * from table1 where id=5
Union all
Select * from table1 where id=3
union all
Select * from table1 where id=4

SQL Two fields from tables of unassociated data into the same field?

I am trying to do this is SQL:
-------------------------------
Table A
-------------------------------
ID | Title
1 | Something Groovy
2 | Something Else
-------------------------------
Table B
-------------------------------
ID | Title
1 | Something Different
2 | Something More
Awesome Select Statement
-------------------------------
Both in one field
-------------------------------
Title
Something Groovy
Something Else
Something Different
Something More
Any Ideas?
Use UNION ALL to obtain the union of two selects. If you want to eliminate duplicates, use simply UNION.
SELECT Title FROM TableA
UNION ALL
SELECT Title FROM TableB
This is a simple union:
Select title from TableA
UNION
Select title from TableB
Note that any items that are identical will be eliminated.