Equivalent of FIRST in Postgresql - postgresql

Edit: Answer is to use MIN. it works on both strings & numbers. Credit to #cadet down below.
Original question:
I've been reading through similar questions around this for the last half an hour and cannot understand the responses so let me try to get a simple easy to follow answer.
What is the PostgresSQL equivalent to this code which I would write if I were using SQL Server, to bring back the first value in field2 when aggregating:
Select field1, first(field2) from table group by field1?
I have read that DISTINCT ON is the right thing to use? In that case would it be:
Select field1, DISTINCT ON(field2) from table group by field1? because that gives me a syntax error
Edit:
Here is the error stating that the FIRST function does not exist in PostGresSQL:
ERROR: function first(asset32type) does not exist
LINE 1: Select policy, first (name) from multi_asset group by policy...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SQL state: 42883
Character: 16
And in case it isn't already clear when I say that in SQL Server the first() function brings back the first value in field2 when aggregating, I mean if you had data like this:
field1
field2
Tom
32
Tom
53
Then select field1, first(field2) group by field1 would give you back:
Tom, 32 - i.e. it picks the first value from field2

Maybe this one, using DISTINCT ON():
SELECT DISTINCT ON (field1)
field1
, field2
FROM table
ORDER BY
field1
, field2;
But without any data or any example, it's just a wild guess.

If first is related with specific order
select distinct field1,
first_value(field2)
over (partition by field1 order by field2) from
(
values (1,10),(1,11),(1,12),(2,23),(2,24)
) as a(field1,field2)
If first is just minimum or maximum
select field1,
min(field2)
from
(
values (1,10),(1,11),(1,12),(2,23),(2,24)
) as a(field1,field2)
group by field1

Related

Db2 convert rows to columns

I need the below results ..
Table :
Order postcode qnty
123 2234 1
Expected result:
Order 123
Postcode 2234
Qnty 1
SQL server:
Select pvt.element_name
,pvt.element_value(select order.postcode
from table name)up
unpivot (element_value for element_name in(order,postcode) as Pvt
How to achieve this in db2?
Db2 for IBM i doesn't have a built-in unpviot function.. AFAIK, it's not available on any Db2 platofrm...unless it's been added recently.
The straight forward method
select 'ORDER' as key, order as value
from mytable
UNION ALL
select 'POSTCODE', postcode
from mytable
UNION ALL
select 'QNTY', char(qnty)
from mytable;
A better performing method is to do a cross join between the source table and a correlated VALUES of as many rows as columns that need to be unpivoted.
select
Key, value
from mytable T,
lateral (values ('ORDER', t.order)
, ('POSTCODE', t.postcode)
, ('QNQTY', varchar(t.qnty))
) as unpivot(key, value);
However, you'll need to know ahead of time what the values you're unpivoting on.
If you don't know the values, there are some ways to unpivot with the XMLTABLE (possibly JSON_TABLE) that might work. I've never used them, and I'm out of time to spend answering this question. You can find some examples via google.
I have created a stored procedure for LUW that rotate a table:
https://github.com/angoca/db2tools/blob/master/pivot.sql
You just need to call the stored procedure by passing the tablename as parameter, and it will return a cursor with the headers of the column in the first column.

postgres, substring a subselect

I have a query that uses a subselect like this
SELECT "columnA","columnB", (SELECT column1 FROM tableB WHERE id=1 LIMIT 1) as text
FROM tableA WHERE id=1
Now i would like to only get the last 3 chars from my "as text" column. I have tried to apply the substring or right around my subselect but that returns an error, can anyone explain why and how to do this properly?
You need to use internal function substring matching POSIX regular expression
SELECT "columnA","columnB", (SELECT substring(column1::TEXT from '...$') FROM tableB WHERE id=1 LIMIT 1) as text
FROM tableA WHERE id=1
Please keep in mind that this way, if you have more than 1 record in tableA that matches your WHERE criteria, you will still be getting the same value in variable text for this query.

How to return a comma separated string using Crystal SQL Expression

I want to display a string on each row (Details section) in my Crystal Report. The contents of this string will be retrieved with the help of a SQL Expression.
The SQL I have is follows: However if multiple rows are returned, I am not sure how to convert that into a Comma Separated String. I have an Oracle 11g database.
(select distinct NAME from TEST
where SAMPLE_NUMBER = "TEST"."SAMPLE_NUMBER"
and X_BENCH <> '"TEST"."X_BENCH"')
The TEST Table looks like this:
My report will be filtered for all samples with a specific test (e.g. Calcium). For those samples on the report, My SQL Expression should retrieve all "Other" Tests on the sample. See output example.
You can accomplish this with a wm_concat. WM_CONCAT takes a bunch of rows in a group and outputs a comma separated varchar.
Using the substr function you can separate the first result with the last.
Please note that I am dirty coding this (without a compiler to check my syntax) so things may not be 100% correct.
select sample_number
, substr(wm_concat(name),1,instr(wm_concat(name),",")-1) as NAME
, substr(wm_concat(name),instr(wm_concat(name),","),length(wm_concat(name)-instr(wm_concat(name),",")+1) as OTHER_TEST_NAMES
from TEST
where SAMPLE_NUMBER = "TEST"."SAMPLE_NUMBER"
and X_BENCH <> '"TEST"."X_BENCH"'
and rownum < 2
group by sample_number
However, if it is not necessary to separate the name and the other test names, it actually is much simpler.
select sample_number
, wm_concat(name) as NAMES
from TEST
where SAMPLE_NUMBER = "TEST"."SAMPLE_NUMBER"
and X_BENCH <> '"TEST"."X_BENCH"'
and rownum < 2
group by sample_number
Also please try to organize your lines to make it easier to read.
You can use LISTAGG for Converting Rows to Comma-Separated String in Oracle.
Example:
SELECT user_id
, LISTAGG(expertise, ',')
WITHIN GROUP (ORDER BY expertise)
AS expertise
FROM TEMP_TABLE
GROUP BY user_id;

nested SELECT statements interact in ways that I don't understand

I thought I understood how I can do a SELECT from the results of another SELECT statement, but there seems to be some sort of blurring of scope that I don't understand. I am using SQL Server 2008R2.
It is easiest to explain with an example.
Create a table with a single nvarchar column - load the table with a single text value and a couple of numbers:
CREATE TABLE #temptable( a nvarchar(30) );
INSERT INTO #temptable( a )
VALUES('apple');
INSERT INTO #temptable( a )
VALUES(1);
INSERT INTO #temptable( a )
VALUES(2);
select * from #temptable;
This will return: apple, 1, 2
Use IsNumeric to get only the rows of the table that can be cast to numeric - this will leave the text value apple behind. This works fine.
select cast(a as int) as NumA
from #temptable
where IsNumeric(a) = 1 ;
This returns: 1, 2
However, if I use that exact same query as an inner select, and try to do a numeric WHERE clause, it fails saying cannot convert nvarchar value 'apple' to data type int. How has it got the value 'apple' back??
select
x.NumA
from
(
select cast(a as int) as NumA
from #temptable
where IsNumeric(a) = 1
) x
where x.NumA > 1
;
Note that the failing query works just fine without the WHERE clause:
select
x.NumA
from
(
select cast(a as int) as NumA
from #temptable
where IsNumeric(a) = 1
) x
;
I find this very surprising. What am I not getting? TIA
If you take a look at the estimated execution plan you'll find that it has optimized the inner query into the outer and combined the WHERE clauses.
Using a CTE to isolate the operations works (in SQL Server 2008 R2):
declare #temptable as table ( a nvarchar(30) );
INSERT INTO #temptable( a )
VALUES ('apple'), ('1'), ('2');
with Numbers as (
select cast(a as int) as NumA
from #temptable
where IsNumeric(a) = 1
)
select * from Numbers
The reason you are getting this is fair and simple. When a query is executed there are some steps that are being followed. This is a parse, algebrize, optimize and compile.
The algebrize part in this case will get all the objects you need for this query. The optimize will use these objects to create a best query plan which will be compiled and executed...
So, when you look into that part you will see it will do a table scan on #temptable. And #temptable is defined as the way you created your table. That you will do some compute on it is a different thing..... The column still has the nvarchar datatype..
To know how this works you have to know how to read a query. First all the objects are retrieved (from table, inner join table), then the predicates (where, on), then the grouping and such, then the select of the columns (with the cast) and then the orderby.
So with that in mind, when you have a combination of selects, the optimizer will still process it that way.. since your select is subordinate to the from and join parts of your query, it will be a reason for getting this error.
I hope i made it a little clear?
The optimizer is free to move expressions in the query plan in order to produce the most cost efficient plan for retrieving the data (the evaluation order of the predicates is not guaranteed). I think using the case expression like bellow produces a NULL in absence of the ELSE clause and thus takes the APPLE out
select a from #temptable where case when isnumeric(a) = 1 then a end > 1

T-SQL usage of Variable with "IN" clause

In our company, the following logic is used in most of SP's. I couldn't understand how a variable is used with the IN Clause like the following query.
Can anyone explain this?
WHERE ( ( #EMP_ID ) in ( select distinct(EMP_ID)
from Table2(nolock)
where SID = T1.SID and status='A' and client_id=T1.Client_Id ) )
order by EMP_ID
The variable is simply replaced in the query. If it helps, break down the query and think of it if you put in a number for the variable (for example, 45) and a list in place of the inner query:
SELECT *
FROM Table
WHERE 45 IN (42, 46, 47, 90, 45)
This will return rows that contain an employee ID of 45.
Does this make sense?
To answer your question: Yes, someone can explain it. Probably not me.
The SELECT gets a collection of EMP_ID values from Table2. The first WHERE clause then checks if the value of variable #EMP_ID is in the set of selected values. If so, the WHERE clause causes its parent statement to process the row.
The SELECT is a correlated subquery. It uses a couple of values, SID and Client_Id, from a table (aliased as) T1. (Said table is not included in your code snippet.) For each row processed from T1 the correlated subquery is evaluated.