Find MAX value on ALN field with special characters in DB2 - db2

Determine the max value of an attribute that has values like below,
GROUPNAME
A-1000
C-1001
A-1002
Expected Output
1002
I tried the below query, and it is giving the output as 1001 instead of 1002, the max value is based on the alphabet rather than the number,
select max(groupname) from table where type in ('A','C') and customer is null
Output
1001

We can use a limit query here:
SELECT *
FROM yourTable
WHERE type IN ('A', 'C') AND customer IS NULL
ORDER BY CAST(SUBSTR(groupname, INSTR(groupname, '-') + 1) AS INT) DESC
LIMIT 1;
The strategy above is to isolate the number which comes after the dash, cast it to an integer, then use that for sorting.

Related

Does my Postgresl column contain only digits?

Is there a way to check if a character varying type column contains only digits or null values with Postgresql?
Maybe something like (this syntax is incorrect):
SELECT *
FROM mytable
ORDER BY
CASE WHEN mycol ~ '^[0-9\.]+$' THEN 1 ELSE 0 END
LIMIT 1
I'm expecting TRUE or FALSE as final result for the whole column.
If you want to to know if the values in all rows are digits, you can use
select not exists (select *
from mytable
where not (mycol ~ '^[0-9\.]+$'))
Online example
To get Nulls use COALESCE(mycol, 1) -- will return 1 if the value in mycol is NULL.
For checking numerics you could use regex LIKE'^[0-9]*' it wont detect decimal dots (dont know if your data have decimals)
BR!

Can't understand why using CAST errors out but using CONVERT does not?

The following code that executes without any issue:
Select
#ICDCodes.ICD_Code,
#ICDCodes.Description,
Count(#DiseaseIndex.VstIntID) AS 'Total Count',
Sum(DATEDIFF(dd,#DiseaseIndex.AdmitDtSrt,#DiseaseIndex.DschrgDtTm )) as 'Total LOS',
ISNULL(AVG(CONVERT(NUMERIC(8,2),DATEDIFF(DAY,#DiseaseIndex.AdmitDtSrt,#DiseaseIndex.DschrgDtTm))),0) as 'Total Avg LOS'
FROM #DiseaseIndex LEFT JOIN #ICDCodes on #DiseaseIndex.VstIntID = #ICDCodes.VstIntID
WHERE ICD_Type IN ('P','S')
GROUP BY #ICDCodes.ICD_Code, #ICDCodes.Descriptio
but this code throws an error:
SELECT
#ICDCodes.ICD_Code,
#ICDCodes.Description,
Count(#DiseaseIndex.VstIntID) AS 'Total Count',
Sum(CAST(DATEDIFF(dd,#DiseaseIndex.AdmitDtSrt,#DiseaseIndex.DschrgDtTm )AS NUMERIC(8,2))) AS 'Total LOS',
ISNULL(CAST(DATEDIFF(DAY,#DiseaseIndex.AdmitDtSrt,#DiseaseIndex.DschrgDtTm) AS NUMERIC(8,2)),0) as 'Total Avg LOS'
FROM #DiseaseIndex LEFT JOIN #ICDCodes on #DiseaseIndex.VstIntID = #ICDCodes.VstIntID
WHERE ICD_Type IN ('P','S')
GROUP BY #ICDCodes.ICD_Code, #ICDCodes.Description`
This is the Error it generates:
Msg 8120, Level 16, State 1, Line 191
Column '#DiseaseIndex.AdmitDtSrt' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Msg 8120, Level 16, State 1, Line 191
Column '#DiseaseIndex.DschrgDtTm' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Basically it is the same code with the exception that one set uses CAST() and the other one uses CONVERT().
Can someone explain why the CAST requires adding the dates to the GROUP BY statement while the CONVERT does not?
Thanks in advance
Update
In the second query you've forgot the AVG:
first query:
ISNULL(AVG(CONVERT(NUMERIC(8,2),DATEDIFF(DAY,#DiseaseIndex.AdmitDtSrt,#DiseaseIndex.DschrgDtTm))),0) as 'Total Avg LOS
second query:
ISNULL(CAST(DATEDIFF(DAY,#DiseaseIndex.AdmitDtSrt,#DiseaseIndex.DschrgDtTm) AS NUMERIC(8,2)),0) as 'Total Avg LOS'
First version:
(This was correct for the first version of the question.)
This is because you use NUMERIC(8,2) in the convert, but DECIMAL(8,2) in the cast.
Though numeric and decimal are documented to be interchangeable synonyms, having a numeric in he group by clause and a decimal in the select clause will raise that error.
Here is a simple demo:
DECLARE #T AS TABLE
(
col1 int,
col2 int
)
INSERT INTO #T VALUES
(1,1),(2,1),(3,1),
(4,2),(5,2),(6,2),
(7,3)
SELECT CAST(Col2 as NUMERIC(8,2)),
AVG(Col1)
FROM #T
GROUP BY CONVERT(DECIMAL(8,2), Col2)
Results:
Column '#T.col2' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
However, if you change the select to decimal or the group by to numeric, the error message is gone and the select returns the result set:
SELECT CAST(Col2 as DECIMAL(8,2)),
AVG(Col1)
FROM #T
GROUP BY CONVERT(DECIMAL(8,2), Col2)
Results:
1.00 2
2.00 5
3.00 7
See a live demo on rextester

select maximum column name from different table in a database

I am comparing from different table to get the COLUMN_NAME of the MAXIMUM value
Examples.
These are example tables: Fruit_tb, Vegetable_tb, State_tb, Foods_tb
Under Fruit_tb
fr_id fruit_one fruit_two
1 20 50
Under Vegetables_tb (v = Vegetables)
v_id v_one V_two
1 10 9
Under State_tb
stateid stateOne stateTwo
1 70 87
Under Food_tb
foodid foodOne foodTwo
1 10 3
Now here is the scenario, I want to get the COLUMN NAMES of the max or greatest value in each table.
You can maybe find out the row which contains the max value of a column. For eg:
SELECT fr_id , MAX(fruit_one) FROM Fruit_tb GROUP BY fr_id;
In order to find the out the max value of a table:
SELECT fr_id ,fruit_one FROM Fruit_tb WHERE fruit_one<(SELECT max(fruit_one ) from Fruit_tb) ORDER BY fr_id DESC limit 1;
A follow up SO for the above scenario.
Maybe you can use GREATEST in order to get the column name which has the max value. But then what I'm not sure is whether you'll be able to retrieve all the columns of different tables at once. You can do something like this to retrieve from a single table:
SELECT CASE GREATEST(`id`,`fr_id`)
WHEN `id` THEN `id`
WHEN `fr_id` THEN `fr_id`
ELSE 0
END AS maxcol,
GREATEST(`id`,`fr_id`) as maxvalue FROM Fruit_tb;
Maybe this SO could help you. Hope it helps!

postgres `order by` argument type

What is the argument type for the order by clause in Postgresql?
I came across a very strange behaviour (using Postgresql 9.5). Namely, the query
select * from unnest(array[1,4,3,2]) as x order by 1;
produces 1,2,3,4 as expected. However the query
select * from unnest(array[1,4,3,2]) as x order by 1::int;
produces 1,4,3,2, which seems strange. Similarly, whenever I replace 1::int with whatever function (e.g. greatest(0,1)) or even case operator, the results are unordered (on the contrary to what I would expect).
So which type should an argument of order by have, and how do I get the expected behaviour?
This is expected (and documented) behaviour:
A sort_expression can also be the column label or number of an output column
So the expression:
order by 1
sorts by the first column of the result set (as defined by the SQL standard)
However the expression:
order by 1::int
sorts by the constant value 1, it's essentially the same as:
order by 'foo'
By using a constant value for the order by all rows have the same sort value and thus aren't really sorted.
To sort by an expression, just use that:
order by
case
when some_column = 'foo' then 1
when some_column = 'bar' then 2
else 3
end
The above sorts the result based on the result of the case expression.
Actually I have a function with an integer argument which indicates the column to be used in the order by clause.
In a case when all columns are of the same type, this can work: :
SELECT ....
ORDER BY
CASE function_to_get_a_column_number()
WHEN 1 THEN column1
WHEN 2 THEN column2
.....
WHEN 1235 THEN column1235
END
If columns are of different types, you can try:
SELECT ....
ORDER BY
CASE function_to_get_a_column_number()
WHEN 1 THEN column1::varchar
WHEN 2 THEN column2::varchar
.....
WHEN 1235 THEN column1235::varchar
END
But these "workarounds" are horrible. You need some other approach than the function returning a column number.
Maybe a dynamic SQL ?
I would say that dynamic SQL (thanks #kordirko and the others for the hints) is the best solution to the problem I originally had in mind:
create temp table my_data (
id serial,
val text
);
insert into my_data(id, val)
values (default, 'a'), (default, 'c'), (default, 'd'), (default, 'b');
create function fetch_my_data(col text)
returns setof my_data as
$f$
begin
return query execute $$
select * from my_data
order by $$|| quote_ident(col);
end
$f$ language plpgsql;
select * from fetch_my_data('val'); -- order by val
select * from fetch_my_data('id'); -- order by id
In the beginning I thought this could be achieved using case expression in the argument of the order by clause - the sort_expression. And here comes the tricky part which confused me: when sort_expression is a kind of identifier (name of a column or a number of a column), the corresponding column is used when ordering the results. But when sort_expression is some value, we actually order the results using that value itself (computed for each row). This is #a_horse_with_no_name's answer rephrased.
So when I queried ... order by 1::int, in a way I have assigned value 1 to each row and then tried to sort an array of ones, which clearly is useless.
There are some workarounds without dynamic queries, but they require writing more code and do not seem to have any significant advantages.

Perl + PostgreSQL-- Selective Column to Row Transpose

I'm trying to find a way to use Perl to further process a PostgreSQL output. If there's a better way to do this via PostgreSQL, please let me know. I basically need to choose certain columns (Realtime, Value) in a file to concatenate certains columns to create a row while keeping ID and CAT.
First time posting, so please let me know if I missed anything.
Input:
ID CAT Realtime Value
A 1 time1 55
A 1 time2 57
B 1 time3 75
C 2 time4 60
C 3 time5 66
C 3 time6 67
Output:
ID CAT Time Values
A 1 time 1,time2 55,57
B 1 time3 75
C 2 time4 60
C 3 time5,time6 66,67
You could do this most simply in Postgres like so (using array columns)
CREATE TEMP TABLE output AS SELECT
id, cat, ARRAY_AGG(realtime) as time, ARRAY_AGG(value) as values
FROM input GROUP BY id, cat;
Then select whatever you want out of the output table.
SELECT id
, cat
, string_agg(realtime, ',') AS realtimes
, string_agg(value, ',') AS values
FROM input
GROUP BY 1, 2
ORDER BY 1, 2;
string_agg() requires PostgreSQL 9.0 or later and concatenates all values to a delimiter-separated string - while array_agg() (v8.4+) creates am array out of the input values.
About 1, 2 - I quote the manual on the SELECT command:
GROUP BY clause
expression can be an input column name, or the name or ordinal number
of an output column (SELECT list item), or ...
ORDER BY clause
Each expression can be the name or ordinal number of an output column
(SELECT list item), or
Emphasis mine. So that's just notational convenience. Especially handy with complex expressions in the SELECT list.