Concatenating fields when BREAK ON command is used - sql

I have built a command that uses the BREAK ON command to stop the output of duplicate field names. For example:
f.name | f.value
f.name | f.value
f.name | f.value
becomes:
f.name | f.value
| f.value
| f.value
Is there any way to have this output as:
f.name | f.value,f.value,f.value
In some instances the f.name field with have over 20 f.values associated with it.
The output will eventually be used to import into other places so I am trying to make the output as friendly as possible.

You're not looking for a SQL*Plus command, you're looking for a string aggregation.
Assuming your current query is:
select name, value from my_table
you can change it as follows to get your desired result. The DISTINCT is included to eliminate duplicate results in your list.
select name, listagg(value, ', ') within group (order by value) as value
from ( select distinct name, value from my_table )
group by name
LISTAGG() was only released in 11.2, if you're using an earlier version of Oracle you could use the undocumented function WM_CONCAT() or the user defined function STRAGG() as outlined in this useful page on string aggregation techniques.

Related

Concatenate rows in function PostgreSQL

Assume there's a table projects containing project name, location, team id, start and end years. How can I concatenate rows so that the same names would combine the other information into one string?
name location team_id start end
Library Atlanta 2389 2015 2017
Library Georgetown 9920 2003 2007
Museum Auckland 3092 2005 2007
Expected output would look like this:
name Records
Library Atlanta, 2389, 2015-2017
Georgetown, 9920, 2003-2007
Museum Auckland, 3092, 2005-2007
Each line should contain end-of-line / new line character.
I have a function for this, but I don't think it would work with just using CONCAT. What are other ways this can be done? What I tried:
CREATE OR REPLACE TYPE projects (name TEXT, records TEXT);
CREATE OR REPLACE FUNCTION records (INT)
RETURNS SETOF projects AS
$$
RETURN QUERY
SELECT p.name
CONCAT(p.location, ', ', p.team_id, ', ', p.start, '-', p.end, CHAR(10))
FROM projects($1) p;
$$
LANGUAGE PLpgSQL;
I tried using CHAR(10) for new line, but its giving a syntax error (not sure why?).
The above sample concatenate the string but expectedly leaving out duplicated names.
You do not need PL/pgSQL for that.
First eliminate duplicate names using DISTINCT and then in a subquery you can concat the columns into a single string. After that use array_agg to create an array out of it. It will then "merge" multiple arrays, in case the subquery returns more than one row. Finally, get rid of the commas and curly braces using array_to_string. Instead of using the char value of a newline, you can simply use E'\n' (E stands for escape):
WITH j (name,location,team_id,start,end_) AS (
VALUES ('Library','Atlanta',2389,2015,2017),
('Library','Georgetown',9920,2003,2007),
('Museum','Auckland',3092,2005,2007)
)
SELECT
DISTINCT q1.name,
array_to_string(
(SELECT array_agg(concat(location,', ',team_id,', ',start,'-', end_, E'\n'))
FROM j WHERE name = q1.name),'') AS records
FROM j q1;
name | records
---------+----------------------------
Library | Atlanta, 2389, 2015-2017
| Georgetown, 9920, 2003-2007
|
Museum | Auckland, 3092, 2005-2007
Note: try to not use reserved strings (e.g. end,name,start, etc.) to name your columns. Although PostgreSQL allows you to use them, it is considered a bad practice.
Demo: db<>fiddle
A bit simple query:
select
name,
string_agg( concat(location, ', ', team_id, ', ', start, '-', "end"), E'\n') AS records
FROM t
group by name;
PostgreSQL fiddle

How to use cursor with LISTAGG in PL/SQL?

I have used LISTAGG to concatenate data from two different tables to form the following output:
How do I display the above output neatly like this:
I am using ORACLE PL/SQL. I am thinking if this can be done by implementing cursor, but I am not sure how to do it. Or maybe is there any other way to achieve this? Thanks.
Looks like NATION.N_NAME column's datatype is CHAR as those names are blank-padded. I'd switch to VARCAHR2 (if possible) or try with TRIM, e.g.
select ...
listagg(trim(n.n_name), ', ') within group ...
----
this
WITH CTE AS
(SELECT r.REGION_KEY
,r.R_NAME
,LIST_AGG(trim(n.N_NAME),',') WITHIN GROUP (ORDER BY R_NAME) AS REGION_NATION
FROM REGION r
INNER JOIN NATION n
ON r.R_REGION_KEY = n.N_REGIONKEY
GROUP BY r.R_REGION_KEY
,r.R_NAME
)
SELECT REGION_KEY
,R_NAME || ':' || REGION_NATION as REGION_TEXT
FROM CTE

Unable to translate BigQuery legacy SQL to standard SQL for HAVING LEFT(...)

I would like to use BigQuery Standard SQL for a query like this one:
SELECT package, COUNT(*) count
FROM (
SELECT REGEXP_EXTRACT(line, r' ([a-z0-9\._]*)\.') package, id
FROM (
SELECT SPLIT(content, '\n') line, id
FROM [github-groovy-files:github.contents]
WHERE content CONTAINS 'import'
HAVING LEFT(line, 6)='import' )
GROUP BY package, id
)
GROUP BY 1
ORDER BY count DESC
LIMIT 30;
I cannot get past something like this (works but doesn't GROUP or COUNT):
with lines as
(SELECT SPLIT(c.content, '\n') line, c.id as id
FROM `<dataset>.contents` c, `<dataset>.files` f
WHERE c.id = f.id AND f.path LIKE '%.groovy')
select
array(select REGEXP_REPLACE(l, r'import |;', '') AS class from unnest(line) as l where l like 'import %') imports, id
from lines;
LEFT() is not in Standard SQL and there doesn't seem to be a function that will accept and array type.
LEFT() is not in Standard SQL ...
In BigQuery Standard SQL you can use SUBSTR(value, position[, length]) instead of Legacy's LEFT
... and there doesn't seem to be a function that will accept and array type.
There are plenty of Array's related functions as well as functions that accept array as argument - for example UNNEST()
I would like to use BigQuery Standard SQL for a query like this one:
Below is equivalent query for BigQuery Standard SQL
SELECT package, COUNT(*) COUNT
FROM (
SELECT REGEXP_EXTRACT(line, r' ([a-z0-9\._]*)\.') package, id
FROM (
SELECT line, id
FROM `github-groovy-files.github.contents`,
UNNEST(SPLIT(content, '\n')) line
WHERE SUBSTR(line, 1, 6)='import'
)
GROUP BY package, id
)
GROUP BY 1
ORDER BY COUNT DESC
LIMIT 30
Instead of WHERE SUBSTR(line, 1, 6)='import' you can use WHERE line LIKE 'import%'
Also note, this query can be written in number of ways - so in my above example I focused on "translating" your query into from legacy to standard sql while preserving core structure and approach of original query
But if you woukld like to rewrite it using power of Standard SQL - you would ended up with something like below
SELECT REGEXP_EXTRACT(line, r' ([a-z0-9\._]*)\.') package, COUNT(DISTINCT id) count
FROM `github-groovy-files.github.contents`,
UNNEST(SPLIT(content, '\n')) line
WHERE line LIKE 'import%'
GROUP BY 1
ORDER BY count DESC
LIMIT 30

Merged multiple values in one record value using SQL [duplicate]

I have a table and I'd like to pull one row per id with field values concatenated.
In my table, for example, I have this:
TM67 | 4 | 32556
TM67 | 9 | 98200
TM67 | 72 | 22300
TM99 | 2 | 23009
TM99 | 3 | 11200
And I'd like to output:
TM67 | 4,9,72 | 32556,98200,22300
TM99 | 2,3 | 23009,11200
In MySQL I was able to use the aggregate function GROUP_CONCAT, but that doesn't seem to work here... Is there an equivalent for PostgreSQL, or another way to accomplish this?
Since 9.0 this is even easier:
SELECT id,
string_agg(some_column, ',')
FROM the_table
GROUP BY id
This is probably a good starting point (version 8.4+ only):
SELECT id_field, array_agg(value_field1), array_agg(value_field2)
FROM data_table
GROUP BY id_field
array_agg returns an array, but you can CAST that to text and edit as needed (see clarifications, below).
Prior to version 8.4, you have to define it yourself prior to use:
CREATE AGGREGATE array_agg (anyelement)
(
sfunc = array_append,
stype = anyarray,
initcond = '{}'
);
(paraphrased from the PostgreSQL documentation)
Clarifications:
The result of casting an array to text is that the resulting string starts and ends with curly braces. Those braces need to be removed by some method, if they are not desired.
Casting ANYARRAY to TEXT best simulates CSV output as elements that contain embedded commas are double-quoted in the output in standard CSV style. Neither array_to_string() or string_agg() (the "group_concat" function added in 9.1) quote strings with embedded commas, resulting in an incorrect number of elements in the resulting list.
The new 9.1 string_agg() function does NOT cast the inner results to TEXT first. So "string_agg(value_field)" would generate an error if value_field is an integer. "string_agg(value_field::text)" would be required. The array_agg() method requires only one cast after the aggregation (rather than a cast per value).
SELECT array_to_string(array(SELECT a FROM b),', ');
Will do as well.
Try like this:
select field1, array_to_string(array_agg(field2), ',')
from table1
group by field1;
Assuming that the table your_table has three columns (name, id, value), the query is this one:
select name,
array_to_string(array_agg(id), ','),
array_to_string(array_agg(value), ',')
from your_table
group by name
order by name
;
"TM67" "4,9,72" "32556,98200,22300"
"TM99" "2,3" "23009,11200"
KI
and the version to work on the array type:
select
array_to_string(
array(select distinct unnest(zip_codes) from table),
', '
);
My sugestion in postgresql
SELECT cpf || ';' || nome || ';' || telefone
FROM (
SELECT cpf
,nome
,STRING_AGG(CONCAT_WS( ';' , DDD_1, TELEFONE_1),';') AS telefone
FROM (
SELECT DISTINCT *
FROM temp_bd
ORDER BY cpf DESC ) AS y
GROUP BY 1,2 ) AS x
In my experience, I had bigint as column type. So The below code worked for me. I am using PostgreSQL 12.
Type cast is happening here. (::text).
string_agg(some_column::text, ',')
Hope below Oracle query will work.
Select First_column,LISTAGG(second_column,',')
WITHIN GROUP (ORDER BY second_column) as Sec_column,
LISTAGG(third_column,',')
WITHIN GROUP (ORDER BY second_column) as thrd_column
FROM tablename
GROUP BY first_column

how to join several row values in one row in postgresql? [duplicate]

I have a table and I'd like to pull one row per id with field values concatenated.
In my table, for example, I have this:
TM67 | 4 | 32556
TM67 | 9 | 98200
TM67 | 72 | 22300
TM99 | 2 | 23009
TM99 | 3 | 11200
And I'd like to output:
TM67 | 4,9,72 | 32556,98200,22300
TM99 | 2,3 | 23009,11200
In MySQL I was able to use the aggregate function GROUP_CONCAT, but that doesn't seem to work here... Is there an equivalent for PostgreSQL, or another way to accomplish this?
Since 9.0 this is even easier:
SELECT id,
string_agg(some_column, ',')
FROM the_table
GROUP BY id
This is probably a good starting point (version 8.4+ only):
SELECT id_field, array_agg(value_field1), array_agg(value_field2)
FROM data_table
GROUP BY id_field
array_agg returns an array, but you can CAST that to text and edit as needed (see clarifications, below).
Prior to version 8.4, you have to define it yourself prior to use:
CREATE AGGREGATE array_agg (anyelement)
(
sfunc = array_append,
stype = anyarray,
initcond = '{}'
);
(paraphrased from the PostgreSQL documentation)
Clarifications:
The result of casting an array to text is that the resulting string starts and ends with curly braces. Those braces need to be removed by some method, if they are not desired.
Casting ANYARRAY to TEXT best simulates CSV output as elements that contain embedded commas are double-quoted in the output in standard CSV style. Neither array_to_string() or string_agg() (the "group_concat" function added in 9.1) quote strings with embedded commas, resulting in an incorrect number of elements in the resulting list.
The new 9.1 string_agg() function does NOT cast the inner results to TEXT first. So "string_agg(value_field)" would generate an error if value_field is an integer. "string_agg(value_field::text)" would be required. The array_agg() method requires only one cast after the aggregation (rather than a cast per value).
SELECT array_to_string(array(SELECT a FROM b),', ');
Will do as well.
Try like this:
select field1, array_to_string(array_agg(field2), ',')
from table1
group by field1;
Assuming that the table your_table has three columns (name, id, value), the query is this one:
select name,
array_to_string(array_agg(id), ','),
array_to_string(array_agg(value), ',')
from your_table
group by name
order by name
;
"TM67" "4,9,72" "32556,98200,22300"
"TM99" "2,3" "23009,11200"
KI
and the version to work on the array type:
select
array_to_string(
array(select distinct unnest(zip_codes) from table),
', '
);
My sugestion in postgresql
SELECT cpf || ';' || nome || ';' || telefone
FROM (
SELECT cpf
,nome
,STRING_AGG(CONCAT_WS( ';' , DDD_1, TELEFONE_1),';') AS telefone
FROM (
SELECT DISTINCT *
FROM temp_bd
ORDER BY cpf DESC ) AS y
GROUP BY 1,2 ) AS x
In my experience, I had bigint as column type. So The below code worked for me. I am using PostgreSQL 12.
Type cast is happening here. (::text).
string_agg(some_column::text, ',')
Hope below Oracle query will work.
Select First_column,LISTAGG(second_column,',')
WITHIN GROUP (ORDER BY second_column) as Sec_column,
LISTAGG(third_column,',')
WITHIN GROUP (ORDER BY second_column) as thrd_column
FROM tablename
GROUP BY first_column