PostgreSQL Sort - sql

I have a sort problem in PostgreSQL with below data:
name
-----
#CF
#CG
CD
CE
I used select name from table order by name, the result as below:
name
-----
CD
CE
#CF
#CE
It seems that Postgres just ignores the special character # and sorts the left string. However, I'd like it sorted like this:
name
-----
#CF
#CG
CD
CE
Searching the internet didn't help. I hope someone here could give a suggestion.

Use PostgreSQL's collation support to tell it you want a particular collation.
Given:
CREATE TABLE t AS VALUES ('CD'),('CE'),('#CF'),('#CE');
You can force byte-wise collation using:
SELECT * FROM t ORDER BY column1 COLLATE "C";
The "C" collation is a byte-wise collation that ignores national language rules, encoding, etc.

Just add that to the order by clause:
ORDER BY CASE WHEN LEFT(name,1) = '#' THEN 0 ELSE 1 END ASC, name ASC

Your undisclosed collation setting obviously ignores the # character for sort order. Either switch to another collation as suggested by #Craig. Or, if you want to stick to your collation for the rest of the string, add a special case for leading #.
In Postgres you can order by boolean values directly. Default order is FALSE, TRUE, NULL.
ORDER BY name !~~ '#%', name
!~~ being the Postgres shorthand for NOT LIKE.

Use this:
SELECT name
FROM table
ORDER BY name WHEN LEFT(name, 1) = '#'
THEN 0 ELSE 1 END, name

Related

How to use multiple values with like in sql

select * from user_table where name in ('123%','test%','dummy%')
How to ensure that this where clause is not an exact match, but a like condition?
In Oracle you can use regexp_like as follows:
select *
from user_table
where regexp_like (name, '^(123|test|dummy)')
The caret (^) requires that the match is at the start of name, and the pipe | acts as an OR.
Be careful though, because with regular expressions you almost certainly lose the benefit of an index that might exist on name.
Use like this,
select *
from user_table
where name LIKE '123%'
OR name LIKE 'test%'
OR name Like 'dummy%';
another option in MySQL
select * from user_table where name REGEXP '^123|^test|^dummy';
To not lose indexed access to rows in Oracle a table collection expression can be used:
SELECT
*
FROM
user_table
JOIN (SELECT column_value filter
FROM table(sys.odcivarchar2list('dummy%', '123%', 'test%'))
) ON user_table.name LIKE filter
The filter expressions must be distinct otherwise you get the same rows from user_table multiple times.

Why can't i refer to a column alias in the ORDER BY using CASE?

Sorry if this a duplicate, but i haven't found one. Why can't i use my column alias defined in the SELECT from the ORDER BY when i use CASE?
Consider this simple query:
SELECT NewValue=CASE WHEN Value IS NULL THEN '<Null-Value>' ELSE Value END
FROM dbo.TableA
ORDER BY CASE WHEN NewValue='<Null-Value>' THEN 1 ELSE 0 END
The result is an error:
Invalid column name 'NewValue'
Here's a sql-fiddle. (Replace the ORDER BY NewValue with the CASE WHEN... that´'s commented out)
I know i can use ORDER BY CASE WHEN Value IS NULL THEN 1 ELSE 0 END like here in this case but actually the query is more complex and i want to keep it as readable as possible. Do i have to use a sub-query or CTE instead, if so why is that so?
Update as Mikael Eriksson has commented any expression in combination with an alias is not allowed. So even this (pointless query) fails for the same reason:
SELECT '' As Empty
FROM dbo.TableA
ORDER BY Empty + ''
Result:
Invalid column name 'Empty'.
So an alias is allowed in an ORDER BY and also an expression but not both. Why, is it too difficult to implement? Since i'm mainly a programmer i think of aliases as variables which could simple be used in an expression.
This has to do with how a SQL dbms resolves ambiguous names.
I haven't yet tracked down this behavior in the SQL standards, but it seems to be consistent across platforms. Here's what's happening.
create table test (
col_1 integer,
col_2 integer
);
insert into test (col_1, col_2) values
(1, 3),
(2, 2),
(3, 1);
Alias "col_1" as "col_2", and use the alias in the ORDER BY clause. The dbms resolves "col_2" in the ORDER BY as an alias for "col_1", and sorts by the values in "test"."col_1".
select col_1 as col_2
from test
order by col_2;
col_2
--
1
2
3
Again, alias "col_1" as "col_2", but use an expression in the ORDER BY clause. The dbms resolves "col_2" not as an alias for "col_1", but as the column "test"."col_2". It sorts by the values in "test"."col_2".
select col_1 as col_2
from test
order by (col_2 || '');
col_2
--
3
2
1
So in your case, your query fails because the dbms wants to resolve "NewValue" in the expression as a column name in a base table. But it's not; it's a column alias.
PostgreSQL
This behavior is documented in PostgreSQL in the section Sorting Rows. Their stated rationale is to reduce ambiguity.
Note that an output column name has to stand alone, that is, it cannot be used in an expression — for example, this is not correct:
SELECT a + b AS sum, c FROM table1 ORDER BY sum + c; -- wrong
This restriction is made to reduce ambiguity. There is still ambiguity if an ORDER BY item is a simple name that could match either an output column name or a column from the table expression. The output column is used in such cases. This would only cause confusion if you use AS to rename an output column to match some other table column's name.
Documentation error in SQL Server 2008
A slightly different issue with respect to aliases in the ORDER BY clause.
If column names are aliased in the SELECT list, only the alias name can be used in the ORDER BY clause.
Unless I'm insufficiently caffeinated, that's not true at all. This statement sorts by "test"."col_1" in both SQL Server 2008 and SQL Server 2012.
select col_1 as col_2
from test
order by col_1;
It seems this limitation is related to another limitation in which "column aliases can't be referenced in same SELECT list". For example, this query:
SELECT Col1 AS ColAlias1 FROM T ORDER BY ColAlias1
Can be translated to:
SELECT Col1 AS ColAlias1 FROM T ORDER BY 1
Which is a legal query. But this query:
SELECT Col1 AS ColAlias1 FROM T ORDER BY ColAlias1 + ' '
Should be translated to:
SELECT Col1 AS ColAlias1, ColAlias1 + ' ' FROM T ORDER BY 2
Which will raise the error:
Unknown column 'ColAlias1' in 'field list'
And finally it seems these are because of SQL standard behaviours not an impossibility in implementation.
More info at: Here
Note: The last query can be executed by MS Access without error but will raise the mentioned error with SQL Server.
You could try something like:
select NewValue from (
SELECT (CASE WHEN Value IS NULL THEN '<Null-Value>' ELSE Value END ) as NewValue,
( CASE WHEN NewValue='<Null-Value>' THEN 1 ELSE 0 END) as ValOrder
FROM dbo.TableA
GROUP BY Value
) t
ORDER BY ValOrder

SQL Server sort order with nonprintable characters

I have a scalar value function that returns a varchar of data containing the ASCII unit seperator Char(31). I am using this result as part of an Order By clause and attempting to sort in ascending order.
My scalar value function returns results like the following (nonprintable character spelled out for reference)
ABC
ABC (CHAR(31)) DEF
ABC (CHAR(31)) DEF (CHAR(31)) HIJ
I would expect that when I order by ascending the results would be the following:
ABC
ABCDEF
ABCDEFHIJ
instead I am seeing the results as the complete opposite:
ABCDEFHIJ
ABCDEF
ABC
Now I am fairly certain that this has to do with the non-printable characters, but I am not sure why. Any idea as to why that is the case?
Thanks
The sortorder can be influenced by your COLLATION settings. Following script, explicitly using Latin1_General_CI_AS as collation orders the items as you would expect.
;WITH q (Col) AS (
SELECT 'ABC' UNION ALL
SELECT 'ABC' + CHAR(31) + 'DEF' UNION ALL
SELECT 'ABC' + CHAR(31) + 'DEF' + CHAR(31) + 'HIJ'
)
SELECT *
FROM q
ORDER BY
Col COLLATE Latin1_General_CI_AS
What collation are you using? You can verify your current database collation settings with
SELECT DATABASEPROPERTYEX('master', 'Collation') SQLCollation;
I am able to duplicate this behavior in SQL Server 2008 R2 with collation set to SQL_Latin1_General_CP1_CI_AS.
If you cannot change your collation settings, set the field to nvarchar instead of varchar. This solved the issue for me.

Is the 'as' keyword required in Oracle to define an alias?

Is the 'AS' keyword required in Oracle to define an alias name for a column in a SELECT statement?
I noticed that
SELECT column_name AS "alias"
is the same as
SELECT column_name "alias"
I am wondering what the consequences are of defining a column alias in the latter way.
According to the select_list Oracle select documentation the AS is optional.
As a personal note I think it is easier to read with the AS
(Tested on Oracle 11g)
About AS:
When used on result column, AS is optional.
When used on table name, AS shouldn't be added, otherwise it's an error.
About double quote:
It's optional & valid for both result column & table name.
e.g
-- 'AS' is optional for result column
select (1+1) as result from dual;
select (1+1) result from dual;
-- 'AS' shouldn't be used for table name
select 'hi' from dual d;
-- Adding double quotes for alias name is optional, but valid for both result column & table name,
select (1+1) as "result" from dual;
select (1+1) "result" from dual;
select 'hi' from dual "d";
AS without double quotations is good.
SELECT employee_id,department_id AS department
FROM employees
order by department
--ok--
SELECT employee_id,department_id AS "department"
FROM employees
order by department
--error on oracle--
so better to use AS without double quotation if you use ORDER BY clause
Both are correct. Oracle allows the use of both.
My conclusion is that(Tested on 12c):
AS is always optional, either with or without ""; AS makes no difference (column alias only, you can not use AS preceding table alias)
However, with or without "" does make difference because "" lets lower case possible for an alias
thus :
SELECT {T / t} FROM (SELECT 1 AS T FROM DUAL); -- Correct
SELECT "tEST" FROM (SELECT 1 AS "tEST" FROM DUAL); -- Correct
SELECT {"TEST" / tEST} FROM (SELECT 1 AS "tEST" FROM DUAL ); -- Incorrect
SELECT test_value AS "doggy" FROM test ORDER BY "doggy"; --Correct
SELECT test_value AS "doggy" FROM test WHERE "doggy" IS NOT NULL; --You can not do this, column alias not supported in WHERE & HAVING
SELECT * FROM test "doggy" WHERE "doggy".test_value IS NOT NULL; -- Do not use AS preceding table alias
So, the reason why USING AS AND "" causes problem is NOT AS
Note: "" double quotes are required if alias contains space OR if it contains lower-case characters and MUST show-up in Result set as lower-case chars. In all other scenarios its OPTIONAL and can be ignored.
The quotes are required when we have a space in Alias Name like
SELECT employee_id,department_id AS "Department ID"
FROM employees
order by department
There is no difference between both, AS is just a more explicit way of mentioning the alias which is good because some dependent libraries depends on this small keyword. e.g. JDBC 4.0. Depend on use of it, different behaviour can be observed.
See this. I would always suggest to use the full form of semantic to avoid such issues.

mysql select all table names except

Alright, I know you can do the following to get all column names.
SHOW COLUMNS FROM person;
However, it does not allow where statements.
Is there any way to get the full list and just say not this one?
So I am basically looking for something like this:
select (show columns from person where Field <> 'id') from person
USe SHOW [FULL] COLUMNS {FROM | IN} tbl_name [{FROM | IN} db_name] [LIKE 'pattern' | WHERE expr]
Example:
SHOW CHARACTER SET WHERE `Default collation` LIKE '%japanese%';
More about show here
Try something like SHOW COLUMNS FROM person WHERE column != 'value';
Or you can use proper a SQL query against information_schema
select * from information_schema.columns
where table_schema = 'test' # your db name
and table_name = 'person '
and column_name != 'id'
For MySQL 4, you can use LIKE directly instead of WHERE http://dev.mysql.com/doc/refman/4.1/en/show-columns.html
SHOW COLUMNS FROM 'Person' LIKE '%x%'
However unfortunately, that does not support a NOT clause.
If I may suggest
If you need this information from
MySQL console/phpAdmin/equivalent,
just eyeball it..
If you need this
from a front-end program like php, do
it from that environment.
MySQL documentation says that WHERE clause is allowed. Read the docs.
You cannot perform a true SHOW COLUMNS WHERE in MySQL 4. The docs show only an optional LIKE parameter for that version: http://dev.mysql.com/doc/refman/4.1/en/show-columns.html
However, you can use the metadatabase information_schema.
USE information_schema;
SELECT * FROM `COLUMNS` WHERE `TABLE_NAME` = 'person' AND `COLUMN_NAME` != 'value';