Ordering by expression from Select - sql

I need to make a query like this:
SELECT (t.a-t.b) AS 'difference'
FROM t
ORDER BY abs(t.a-t.b)
Is there a way not to duplicate code (t.a-t.b) ? Thank you for your answers

You can wrap the SQL statement and then perform the ORDER BY if you're performing an absolute value on it.
SELECT * FROM
(
SELECT (t.a-t.b) AS "difference"
FROM t
) a
ORDER BY abs(a.difference)
UPDATE: I used SQL Server the 1st time, but depending on your environment (Oracle, MySQL), you may need to include double quotes around the column alias, so:
SELECT * FROM
(
SELECT (t.a-t.b) AS "difference"
FROM t
) a
ORDER BY abs("a.difference")

Related

Using calculation with an an aliased column in ORDER BY

As we all know, the ORDER BY clause is processed after the SELECT clause, so a column alias in the SELECT clause can be used.
However, I find that I can’t use the aliased column in a calculation in the ORDER BY clause.
WITH data AS(
SELECT *
FROM (VALUES
('apple'),
('banana'),
('cherry'),
('date')
) AS x(item)
)
SELECT item AS s
FROM data
-- ORDER BY s; -- OK
-- ORDER BY item + ''; -- OK
ORDER BY s + ''; -- Fails
I know there are alternative ways of doing this particular query, and I know that this is a trivial calculation, but I’m interested in why the column alias doesn’t work when in a calculation.
I have tested in PostgreSQL, MariaDB, SQLite and Oracle, and it works as expected. SQL Server appears to be the odd one out.
The documentation clearly states that:
The column names referenced in the ORDER BY clause must correspond to
either a column or column alias in the select list or to a column
defined in a table specified in the FROM clause without any
ambiguities. If the ORDER BY clause references a column alias from
the select list, the column alias must be used standalone, and not as
a part of some expression in ORDER BY clause:
Technically speaking, your query should work since order by clause is logically evaluated after select clause and it should have access to all expressions declared in select clause. But without looking at having access to the SQL specs I cannot comment whether it is a limitation of SQL Server or the other RDBMS implementing it as a bonus feature.
Anyway, you can use CROSS APPLY as a trick.... it is part of FROM clause so the expressions should be available in all subsequent clauses:
SELECT item
FROM t
CROSS APPLY (SELECT item + '') AS CA(item_for_sort)
ORDER BY item_for_sort
It is simply due to the way expressions are evaluated. A more illustrative example:
;WITH data AS
(
SELECT * FROM (VALUES('apple'),('banana')) AS sq(item)
)
SELECT item AS s
FROM data
ORDER BY CASE WHEN 1 = 1 THEN s END;
This returns the same Invalid column name error. The CASE expression (and the concatenation of s + '' in the simpler case) is evaluated before the alias in the select list is resolved.
One workaround for your simpler case is to append the empty string in the select list:
SELECT
item + '' AS s
...
ORDER BY s;
There are more complex ways, like using a derived table or CTE:
;WITH data AS
(
SELECT * FROM (VALUES('apple'),('banana') AS sq(item)
),
step2 AS
(
SELECT item AS s FROM data
)
SELECT s FROM step2 ORDER BY s+'';
This is just the way that SQL Server works, and I think you could say "well SQL Server is bad because of this" but SQL Server could also say "what the heck is this use case?" :-)

Use of asterisk in oracle sql

Why is the use of asterisk perfectly valid in oracle sql when the asterisk is by itself in the SELECT clause, but it results in an error when there are other expressions in the SELECT?
For example:
select * from table1 -- is ok
But:
select field, * from table -- is not ok
Oracle only allows a "bare" asterisk when there are no other columns.
Otherwise, you need to qualify it:
select t.field, t.*
from table1 t;
I suspect the reason is that Oracle considers select * to be a full clause, rather than * being an abbreviation for all columns.

SQL simple GROUP BY query

Is there a way to make a simple GROUP BY query with SQL and not use COUNT,AVG or SUM? I want to show all columns and group it with a single column.
SELECT * FROM [SPC].[dbo].[BoardSFC] GROUP BY boardsn
The query above is working on Mysql but not on SQL, is there a way to achieve this? any suggestion would be great
UPDATE: Here is my data I just need to group them by boardsn and get imulti equals to 1
I thing you just understand 'group data' in a different way than it is implemented in sql server. You simply want rows that have the same value together in the result and that would be ordering not grouping. So maybe what you need is:
SELECT *
FROM [SPC].[dbo].[BoardSFC]
WHERE imulti = 1
ORDER BY boardsn
The query above is working on Mysql but not on SQL, is there a way to achieve this? any suggestion would be great
No, there is not. MySQL only lets you do this because it violates the various SQL standards quite egregiously.
You need to name each column you want in the result-set whenever you use GROUP BY. The SELECT * feature is only provided as a convenience when working with data interactively - in production code you should never use SELECT *.
You could use a TOP 1 WITH TIES combined with a ORDER BY ROW_NUMBER.
SELECT TOP 1 WITH TIES *
FROM [SPC].[dbo].[BoardSFC]
ORDER BY ROW_NUMBER() OVER (PARTITION BY boardsn ORDER BY imulti)
Or more explicitly, use ROW_NUMBER in a sub-query
SELECT *
FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY boardsn ORDER BY imulti) as RN
FROM [SPC].[dbo].[BoardSFC]
) q
where RN = 1

select row of minimum value without using rownum

I'm using Oracle SQL and i need some help with a query.
In the following query i'm selecting some rows with a simple condition (never mind hat kind of). From the output rows, i need to select the row with minimum value of DATE. For that, i'm using ROWNUM.
SELECT *
FROM(
SELECT NAME, DATE
FROM LIST
WHERE NAME = 'BLABLA'
ORDER by DATE)
WHERE ROWNUM = 1;
However, this query must fit to any other SQL languages, and therefore i need to write this query without ROWNUM.
Is there a simple way to write this query without using ROWNUM?
Unfortunately, row limit syntax differs between RDBMS.
The following is portable between SqlServer, Oracle and PostGres:
SELECT *
FROM (
SELECT NAME, DATE, ROW_NUMBER() OVER (ORDER by DATE) AS RowNum
FROM LIST
WHERE NAME = 'BLABLA'
) X
WHERE RowNum = 1;
However, other DB's syntax is different, e.g. MySql's LIMIT
select * from LIST
where Date=(select min(date) from LIST where Name='BLABLA' )
and Name='BLABLA'

Distinct with select *

Is it possible to use select * with distinct or write easily something that has the same impact?
I need to select all columns from a table with distinct value, but listing all the columns in select clause would be nerve-breaking because the number of columns is over 20!
In Microsoft SQL Server you can write:
select distinct * from MyTable
However, it is considered "best practice" to specify the columns explicitly, partly because it improves the performance of the query, but also to protect yourself from failures that would arise if the database schema were to change in the future
This should work:
SELECT DISTINCT * FROM TABLE_NAME
Use this query:
SELECT DISTINCT Employee, Rank
FROM Employees
Adding the "distinct" keyword right after "select" does the work.
For example:
SELECT DISTINCT * FROM TABLE_NAME