Use result of query in a function (postgres 8.3) - sql

I am trying to do something like this:
select char_length(select text_field from table where key = 1)
This won't work, and I presume, because the return type of a query is a table, not a string or text variable.
Is there a way to specify row,col of the result from a select statement?
edit: I overlooked to mention, that char_length is a function.

When passing the result of a query to a function, simply wrap the query in brackets:
select char_length((select text_field from table where key = 1));
The outer set of brackets is for the function, the inner set converts a query to a result.
This syntax is not specific to postgres - it applies to all SQL servers.
This link shows the above code executing correctly (thanks to #Fahim Parkar for this)
Although, you could re-factor your query to not require this syntax, nevertheless this is how you "pass the result of a query to a function".

select char_length(text_field) from "table" where key = 1

Assuming key is a primary key or unique key the first example below will work. It works only if the sub-query returns only 1 row. The second example will work for 1 or more rows.
select char_length((select text_field from table where key = 1));
select char_length(text_field) from table where key = 1;

It should be
select char_length(text_field) from "table" where key = 1
Also I believe, your table name is not table.

Related

How to backreference a calculated column value in another column during an INSERT query on Postgres? (query-runtime temporary variable assignment)

In MySQL there's some helpful syntax for doing things like SELECT #calc:=3,#calc, but I can't find the way to solve this on PostgreSQL
The idea would be something like:
SELECT (SET) autogen := UUID_GENERATE_v4() AS id, :autogen AS duplicated_id;
returning a row with 2 columns with same value
EDIT: Not interested in conventional \set, I need to do this for hundreds of rows
You can use a subquery:
select id, id as duplicated_id
from (select UUID_GENERATE_v4() AS id
) x
Postgres does not confuse the select statement by allowing variable assignment. Even if it did, nothing guarantees the order of evaluation of expressions in a select, so you still would not be sure that it worked.

One select for multiple records by composite key

Such a query as in the title would look like this I guess:
select * from table t where (t.k1='apple' and t.k2='pie') or (t.k1='strawberry' and t.k2='shortcake')
... --10000 more key pairs here
This looks quite verbose to me. Any better alternatives? (Currently using SQLite, might use MYSQL/Oracle.)
You can use for example this on Oracle, i assume that if you use regular concatenate() instead of Oracle's || on other DB, it would work too (as it is simply just a string comparison with the IN list). Note that such query might have suboptimal execution plan.
SELECT *
FROM
TABLE t
WHERE
t.k1||','||t.k2 IN ('apple,pie',
'strawberry,shortcake' );
But if you have your value list stored in other table, Oracle supports also the format below.
SELECT *
FROM
TABLE t
WHERE (t.k1,t.k2) IN ( SELECT x.k1, x.k2 FROM x );
Don't be afraid of verbose syntax. Concatenation tricks can easily mess up the selectivity estimates or even prevent the database from using indexes.
Here is another syntax that may or may not work in your database.
select *
from table t
where (k1, k2) in(
('apple', 'pie')
,('strawberry', 'shortcake')
,('banana', 'split')
,('raspberry', 'vodka')
,('melon', 'shot')
);
A final comment is that if you find yourself wanting to submit 1000 values as filters you should most likely look for a different approach all together :)
select * from table t
where (t.k1+':'+t.k2)
in ('strawberry:shortcake','apple:pie','banana:split','etc:etc')
This will work in most of the cases as it concatenate and finds in as one column
off-course you need to choose a proper separator which will never come in the value of k1 and k2.
for e.g. if k1 and k2 are of type int you can take any character as separator
SELECT * FROM tableName t
WHERE t.k1=( CASE WHEN t.k2=VALUE THEN someValue
WHEN t.k2=otherVALUE THEN someotherValue END)
- SQL FIDDLE

SQL with LIMIT1 returns all records

I made a mistake and entered:
SELECT * FROM table LIMIT1
instead of
SELECT * FROM table LIMIT 1 (note the space between LIMIT and 1)
in the CLI of MySQL. I expected to receive some kind of parse error, but I was surprised, because the query returned all of the records in the table. My first thought was "stupid MySQL, I bet that this will return error in PostgreSQL", but PostgreSQL also returned all records. Then tested it with SQLite - with the same result.
After some digging, I realized that it doesn't matter what I enter after the table. As long as there are no WHERE/ORDER/GROUP clauses:
SELECT * FROM table SOMETHING -- works and returns all records in table
SELECT * FROM table WHERE true SOMETHING -- doesn't work - returns parse error
I guess that this is a standardized behavior, but I couldn't find any explanation why's that. Any ideas?
Your first query is equivalent to this query using a table alias:
SELECT * FROM yourtable AS LIMIT1
The AS keyword is optional. The table alias allows you to refer to columns of that table using the alias LIMIT1.foo rather than the original table name. It can be useful to use aliases if you wish to give tables a shorter or a more descriptive alias within a query. It is necessary to use aliases if you join a table to itself.
From the SQL lite documentation:
This is why I want DB engine to force the usage of keyword AS for alias names
http://beyondrelational.com/modules/2/blogs/70/posts/10814/should-alias-names-be-preceded-by-as.aspx
SELECT * FROM table LIMIT1;
LIMIT1 This has taken as alias by SQL, cause LIMIT1 is not a reserved literal of SQL.
Something after table name and that is not a reserved keyword always taken as an table alias by SQL.
SELECT * FROM table LIMIT 1;
When you used LIMIT just after the table name, SQL found that as a reserved keyword and worked for it as per the behavior. IF you want to use reserved key words in query It can be done by putting reserved literals in quotes. like..
SELECT * FROM table `LIMIT`;
OR
SELECT * FROM table `LIMIT 1`;
Now all words covered under `` quotes will treated as user defined.
Commonly we did mistake with date, timestamp, limit etc.. keywords by using them as column names.

Select query to retrieve the value of primary key for a specific row in a table

I am struggling to retrieve the value of primary key for a table. We are using MS SQL Server 2005. The database was designed years back by somebody else (he didn't follow the normalization rules at all). He used Key (which is a keyword in sql server) as the column name for primary key of a table. So I cannot use query like this: select key from table_name where column2 = ?
Could anyone help to write a query to get the value of the primary key for a specific row something like this: select primary_key from tbale_name where column2 = ?
Yes you can, simply wrap column names in backticks:
select `key` from `table_name` where `column2` = ?
Alternatively, depending on your DB, you might use square brackets:
select table_name.[key] from table_name where table_name.[column2] = ?
Edit: I see you said "MS SQL". I think that one works with the square brackets. MySQL accepts the backtick syntax.

Postgresql - Using subqueries with alter sequence expressions

Is it possible to use subqueries within alter expressions in PostgreSQL?
I want to alter a sequence value based on a primary key column value.
I tried using the following expression, but it wouldn't execute.
alter sequence public.sequenceX restart with (select max(table_id)+1 from table)
I don't believe you can do it like that but you should be able to use the setval function direction which is what the alter does.
select setval('sequenceX', (select max(table_id)+1 from table), false)
The false will make it return the next sequence number as exactly what is given.
In addition if you have mixed case object names and you're getting an error like this:
ERROR: relation "public.mytable_id_seq" does not exist
... the following version using regclass should be useful:
select setval('"public"."MyTable_Id_seq"'::regclass, (select MAX("Id") FROM "public"."MyTable"))