Order By clause in sql server - sql

Suppose, there is a table and I need to sort one of its column (name) alphabetically and at the same time I want to sort it by using ID column in asc order based on the condition ( rows that have same name). So, I failed to understand how this will work. Once the records will be sorted by column (name) then will it sort all rows by using id column?
Can someone explain how actually order by clause works in this case
select name,
id
from hack h
order by name,
id

use order by name, id
select name,
id
from hack
order by name,
id

I just tried to understand what you want to know, you want to realize how it happens when the order by clause have two or more columns ,am I right? Let's go to an example,
the first column is id and the second is name,
2 A
5 B
6 A
3 A
1 B
the result of SQL "select name,id from hack order by name,id" will get the result as below
A 2
A 3
A 6
B 1
B 5
see, it will sort first by name column, and then sort id in the same name value group.
That's it ,did I make it clear?

This answers the original question.
In the code you posted:
substring(name, len(name) - 2, len(name))
returns the last 3 characters of the name.
So you are sorting by these last 3 characters and not by name.
When there are 2 names with the same last 3 characters these will be sorted by id.

If there are more than one column names after "order by" keyword, the system orders the records according to the first column just after order by.

Related

Valid SQL causes Access error requiring expression in SELECT and GROUP? [duplicate]

I have this:
SELECT name, value,
MIN(value) as find_min
FROM history
WHERE date_num >= 1609459200
AND date_num <= 1640995200
AND name IN('A')
GROUP BY name
Trying to get the minimum value between dates for each subject separately :
name value
A. 3
B 4
C 9
A 0
C 2
I keep getting this popular error:
column "history.value" must appear in the GROUP BY clause or be used in an aggregate function
I read this must appear in the GROUP BY clause or be used in an aggregate function
and I still do not understand:
Why I have to include in GROUP BY everything? what is the logic?
Why is this not working?
is Min() over (partition by name) better, and if so, how can I get only a single result per name?
EDIT:
If I try:GROUP BY name, find_min it will fail as well, even though in this case he can produce a unique result (the all the same)
That is actually easy to understand.
When you say GROUP BY name, all rows where name is the same are grouped together to form a single result row. Now the original table could contain two rows with the same name, but different value. If you add value to the SELECT list, which of those should be output? On the other hand, determining min(value) for each group is no problem.
Even if there is only a single value for the whole group (like with your find_min), you have to add the column to GROUP BY.
There is actually one exception: if the primary key of a table is in the GROUP BY clause, other columns from that table need not be in GROUP BY, because this proves automatically that there can be no different values.
try like below
SELECT name,
MIN(value) as find_min
FROM history
WHERE date_num >= 1609459200 AND date_num <= 1640995200
GROUP BY name
I removed name in ('A') because your are searching for all name min value so it will restrict just A
To answer your question, GROUP BY groups similar data in a table.
For example this table:
A B C
a d 1
a k 2
b d 3
And you have the query:
SELECT A, B, MIN(C)
FROM t
GROUP BY A
and this would not work you can't give a decisive answer what to do with the entry a k 2 because you don't group by Column B, but you group by column A, is there now two entries but they are different. Therefore you have to group by all non min,max,sum,etc. columns.

Why column must appear in the GROUP BY?

I have this:
SELECT name, value,
MIN(value) as find_min
FROM history
WHERE date_num >= 1609459200
AND date_num <= 1640995200
AND name IN('A')
GROUP BY name
Trying to get the minimum value between dates for each subject separately :
name value
A. 3
B 4
C 9
A 0
C 2
I keep getting this popular error:
column "history.value" must appear in the GROUP BY clause or be used in an aggregate function
I read this must appear in the GROUP BY clause or be used in an aggregate function
and I still do not understand:
Why I have to include in GROUP BY everything? what is the logic?
Why is this not working?
is Min() over (partition by name) better, and if so, how can I get only a single result per name?
EDIT:
If I try:GROUP BY name, find_min it will fail as well, even though in this case he can produce a unique result (the all the same)
That is actually easy to understand.
When you say GROUP BY name, all rows where name is the same are grouped together to form a single result row. Now the original table could contain two rows with the same name, but different value. If you add value to the SELECT list, which of those should be output? On the other hand, determining min(value) for each group is no problem.
Even if there is only a single value for the whole group (like with your find_min), you have to add the column to GROUP BY.
There is actually one exception: if the primary key of a table is in the GROUP BY clause, other columns from that table need not be in GROUP BY, because this proves automatically that there can be no different values.
try like below
SELECT name,
MIN(value) as find_min
FROM history
WHERE date_num >= 1609459200 AND date_num <= 1640995200
GROUP BY name
I removed name in ('A') because your are searching for all name min value so it will restrict just A
To answer your question, GROUP BY groups similar data in a table.
For example this table:
A B C
a d 1
a k 2
b d 3
And you have the query:
SELECT A, B, MIN(C)
FROM t
GROUP BY A
and this would not work you can't give a decisive answer what to do with the entry a k 2 because you don't group by Column B, but you group by column A, is there now two entries but they are different. Therefore you have to group by all non min,max,sum,etc. columns.

How can I separate same column values to a variable based on value in another column?

suppose I Have below table
A
B
1
one
2
two
1
three
2
four
1
last
for value in A=1
then I need the output as one;three;last
how can I query this in Oracle's SQL?
If you care whether you get the string "one;three;last" or "three;one;last" or some other combination of the three values, you'd need some additional column to order the results by (a database table is inherently unordered). If there is an id column that you're not showing, for example, that could do that, you'd order by id in the listagg.
If you don't care what order the values appear in the result, you could do something like this
select listagg( b, ';' ) within group (order by a)
from your_table
where a = 1

MySQL - Is it possible to achieve this using SQL?

Imagine you've got a table with 2 columns: ID and NAME. ID is simply a number, incrementing for each row (as you'd expect). NAME is some random varchar string. NAME can be same for different rows. Now, imagine you want to get the 3 latest occurences in this table, where NAME only may occur once.
For example, if you've got this data:
ID NAME
1 HELLO
2 TEST
3 HELLO
4 HELLO
5 QWERTY
6 HELLO
Then the result of the question should be:
6 HELLO
5 QWERTY
2 TEST
Is it possible achieve this on SQL level?
SELECT
MAX(ID),
Name
FROM
table
GROUP BY
Name
ORDER BY
MAX(ID) desc
LIMIT 3
SELECT MAX(ID), NAME
FROM THAT_TABLE
GROUP BY NAME
See: GROUP BY (Aggregate) Functions
I suppose, you need to use "DISTINCT" for the "name" column:
SELECT DISTINCT name, id FROM table_name ORDER BY id DESC LIMIT 3;
Another way to achieve this is to use "GROUP BY" for "name" (see another answer)

How to select 10 rows below the result returned by the SQL query?

Here is the SQL table:
KEY | NAME | VALUE
---------------------
13b | Jeffrey | 23.5
F48 | Jonas | 18.2
2G8 | Debby | 21.1
Now, if I type:
SELECT *
FROM table
WHERE VALUE = 23.5
I will get the first row.
What I need to accomplish is to get the first and the next two rows below. Is there a way to do it?
Columns are not sorted and WHERE condition doesn't participate in the selection of the rows, except for the first one. I just need the two additional rows below the returned one - the ones that were entered after the one which has been returned by the SELECT query.
Without a date column or an auto-increment column, you can't reliably determine the order the records were entered.
The physical order with which rows are stored in the table is non-deterministic.
You need to define an order to the results to do this. There is no guaranteed order to the data otherwise.
If by "the next 2 rows after" you mean "the next 2 records that were inserted into the table AFTER that particular row", you will need to use an auto incrementing field or a "date create" timestamp field to do this.
If each row has an ID column that is unique and auto incrementing, you could do something like:
SELECT * FROM table WHERE id > (SELECT id FROM table WHERE value = 23.5)
If I understand correctly, you're looking for something like:
SELECT * FROM table WHERE value <> 23.5
You can obviously write a program to do that but i am assuming you want a query. What about using a Union. You would also have to create a new column called value_id or something in those lines which is incremented sequentially (probably use a sequence). The idea is that value_id will be incremented for every insert and using that you can write a where clause to return the remaining two values you want.
For example:
Select * from table where value = 23.5
Union
Select * from table where value_id > 2 limit 2;
Limit 2 because you already got the first value in the first query
You need an order if you want to be able to think in terms of "before" and "after".
Assuming you have one you can use ROW_NUMBER() (see more here http://msdn.microsoft.com/en-us/library/ms186734.aspx) and do something like:
With MyTable
(select row_number() over (order by key) as n, key, name, value
from table)
select key, name, value
from MyTable
where n >= (select n from MyTable where value = 23.5)