How to select id, first_not_null(value1), first_not_null(value2).. on Postgresql - performance

I have a table like this:
+--+---------+---------+
|id|str_value|int_value|
+--+---------+---------+
| 1| 'abc' | |
| 1| | 1 |
| 2| 'abcd' | |
| 2| | 2 |
+--+---------+---------+
I need to get this:
+--+---------+---------+
|id|str_value|int_value|
+--+---------+---------+
| 1| 'abc' | 1 |
| 2| 'abcd' | 2 |
+--+---------+---------+
It seems to me that I need something like:
select id, first_not_null(str_value), first_not_null(int_value)
from table
group by id
Is there any acceptable way to do this? I use Postgresql 9.0.1.
Update: this should work with uuid types as well

You should look at http://www.postgresql.org/docs/8.1/static/functions-aggregate.html for aggregate functions.
I guess max should do the work
EDIT: Working example
select id, max(col1), max(col2) from (
select 1 as id, null as col1, 'test' as col2
union
select 1 as id ,'blah' as col1, null as col2
) x group by id

Related

How to display N/A when Name column is blank for custid1 in ID column and for custid2 we have 2 entries as 1.Prem, 2. (2 is blank)

I have a table like below,I'm using vertica data base sql
| Name | Cust ID |
| | 1 |
| | 2 |
|Prem | 2 |
For cust ID 1 the name is blank, so it should display and N/A, for cust ID 2 we have 2 entries, which are 1 is blank and 2 is Prem, so blank should be ignored and should display Prem.
The final out put should be like this,
|Name | Cust ID |
|N/A |1 |
|Prem |2 |
The final output should be like this,
|Name | Cust ID |
|N/A |1 |
|Prem |2 |
This works if the non-empty name of the same cust-id is always the same in multiple rows. Note that I use the NULL value for non-existent data. An empty string and NULL are two different things, for me.
WITH
indata("name",custid) AS (
SELECT NULL , 1
UNION ALL SELECT NULL , 2
UNION ALL SELECT 'Prem', 2
)
SELECT
IFNULL(MAX("name"),'N/A') AS "name"
, custid
FROM indata
GROUP BY custid;
-- out Null display is "(null)".
-- out name | custid
-- out ------+--------
-- out N/A | 1
-- out Prem | 2

Delete query inoracle db is fast but select query running too long

I have below table with 160,000 rows. When I use SELECT ID FROM mytable WHERE id NOT IN ( SELECT max(id) FROM mytable GROUP BY user_id); query is running very long and not finishing (I wait for 1 Hr) but when I use delete FROM mytable WHERE id NOT IN (SELECT max(id) FROM mytable GROUP BY user_id); query is running in 0.5 seconds. Why??
---------------------------------------------------------------------------------------------------
| id | MyTimestamp | Name | user_id ...
----------------------------------------------------------------------------------------------------
| 0 | 1657640396 | John | 123581 ...
| 1 | 1657638832 | Tom | 168525 ...
| 2 | 1657640265 | Tom | 168525 ...
| 3 | 1657640292 | John | 123581 ...
| 4 | 1657640005 | Jack | 896545 ...
-----------------------------------------------------------------------------------------

Oracle SQL: Display single columns from multiple rows of a single table with Logic

Oracle SQL
I would like to look-up data from 2 rows of the same column from the same table together in an existing long query with multiple joins.
Current table set-up (single table):
Table: ACCOUNT_DETAILS
| TRX_ID | TYPE | FAC_ID | ACC_ID |
| ------ | ---- | ------ | ------ |
| 1234 | CRDR | ABC123 | AB1234 |
| 1234 | DBTR | XYZ222 | XY9800 |
| 9876 | CRDR | EFG999 | EF7659 |
| 9876 | DBTR | ABC123 | AB9900 |
Expected Result:
Table: REPORT
| TRX_ID | Counterparty FAC_ID | Counterparty ACC_ID |
| ------ | ------------------- | ------------------- |
| 1234 | XYZ222 | XY9800 |
| 9876 | EFG999 | EF7659 |
Logic needed:
If FAC_ID NOT LIKE 'ABC%' then refer to the Counterparty FAC_ID (e.g. for TRX_ID = 1234, it will refer to the DBTR FAC_ID and DBTR ACC_ID; TRX_ID = 9876, it will refer to the CRDR FAC_ID AND CRDR ACC_ID)
Example:
SELECT (CASE WHEN TYPE = 'DBTR' AND FAC_ID LIKE 'ABC%' THEN (SELECT FAC_ID FROM ACCOUNT_DETAILS WHERE TYPE = 'CRDR')
ELSE (SELECT FAC_ID FROM ACCOUNT_DETAILS WHERE TYPE = 'DBTR') END)
FROM ACCOUNT_DETAILS
I've tried options such as JOINs, UNIONs and subqueries but it does not work. I would like to have the Counterparty FAC_ID and Counterparty ACC_IDs in separate single lines in the query, as I will include it in a long query that I already have.
We can use CASE in a CTE to flag the rows where FAC_ID does not start with "ABC" and then use the flag in the WHERE clause.
See db<>fiddle here for schema.
with cte as
(
select
TRX_ID,
FAC_ID,
ACC_ID,
CASE WHEN FAC_ID LIKE 'ABC%' THEN 0 ELSE 1 END ordinal
FROM ACCOUNT_DETAILS)
SELECT
TRX_ID,
FAC_ID,
ACC_ID
FROM CTE
WHERE ordinal = 1;
TRX_ID | FAC_ID | ACC_ID
-----: | :----- | :-----
1234 | XYZ222 | XY9800
9876 | EFG999 | EF7659
db<>fiddle here

Convert raw query into laravel eloquent

I have this written and working as a raw SQL query, but I am trying to convert it to a more Laravel eloquent / query builder design instead of just a raw query.
My table structure like this:
Table One (Name model)
______________
| id | name |
|------------|
| 1 | bob |
| 2 | jane |
--------------
Table Two (Date Model)
_________________________________
| id | table_1_id | date |
|-------------------------------|
| 1 | 1 | 2000-01-01 |
| 2 | 1 | 2000-01-31 |
| 4 | 1 | 2000-02-28 |
| 5 | 1 | 2000-03-03 |
| 6 | 2 | 2000-01-03 |
| 7 | 2 | 2000-01-05 |
---------------------------------
I am returning only the the highest (most recent) dates from table 2 (Dates model) that match the user bob from table 1 (Name model).
For instance, in the example above, I return this from my query
2000-01-31
2000-02-28
2000-03-03
Here is what I am doing now (which works), but i'm just not sure how to use YEAR, MONTH and MAX with laravel.
DB::select(
DB::raw("
SELECT MAX(date) as max_date
FROM table_2
INNER JOIN table_1 ON table_1.id = table_2.table_1_id
WHERE table_1.name = 'bob'
GROUP BY YEAR(date), MONTH(date)
ORDER BY max_date DESC
")
);
Try this code if any problem then,
DB::table('table_1')->join('table_2', 'table_1.id','=','table_2.table_1_id')
->select(DB::raw('MAX(date) as max_date'),DB::raw('YEAR(date) year, MONTH(date) month'),'table_1.name')
->where('name','bob')
->groupBy('year','month')
->orderBy('max_date')
->get();
If any problem with above code then feel free to ask.

Column to comma separated value in Hive

It's been asked and answered for SQL (Convert multiple rows into one with comma as separator), would any of the approaches mentioned work in Hive, e.g. to go from this:
+------+------+
| Col1 | Col2 |
+------+------+
| a | 1 |
| a | 5 |
| a | 6 |
| b | 2 |
| b | 6 |
+------+------+
to this:
+------+-------+
| Col1 | Col2 |
+------+-------+
| a | 1,5,6 |
| b | 2,6 |
+------+-------+
The aggregator function collect_set can achieve what you are trying to get. Here is the documentation. So you can write a query like:
SELECT Col1, collect_set(Col2)
FROM your_table
GROUP BY Col1;
However, there is one striking difference between MySQL's GROUP BY and Hive's collect_set that while GROUP_CONCAT also retains duplicates in the resulting array, collect_set removes the duplicates occuring in the array. In the example shown by you there are no repeating group values for Col2 so you can go ahead and use it.
And there is collect_list that will take full list (with duplicates).
Try this
SELECT Col1, concat_ws(',', collect_set(Col2)) as col2
FROM your_table
GROUP BY Col1;
apache.org documentation

Resources