How to select multiple row in postgresql? - sql

I can give a result set consisting of a single value, say 1, as follows:
SELECT 1 as column;
and it gives me the result set:
column
------
1
But I have a list of such values represented as a string (1, 4, 7, ...) and I need to produce the following result set:
column
------
1
4
7
.
.
.
I tried SELECT * FROM (1, 4, 7) but it didn't work. I also tried to SELECT 1, 4, 7 but it produces the following result set:
col1 col2 col3
1 4 7
Which was not what I was looking for.

If those are constant values, you can use the values clause:
select *
from (
values (1), (4), (7)
) as t(id);
If your values are inside a string literal, you can use this:
select *
from unnest(string_to_array('1,2,3,4', ',')) as id;

You could unnest it as an array:
SELECT UNNEST(ARRAY[1, 4, 7])

You can use the union To get what you want.But if this is the sting as 1,4,7 comma seprated then you need to use the regexp_split_to_table function. Mentioned here and here
Select 1
UNION
select 4
UNION
select 7

Related

How to find each case of matching pattern within a string and return as rows

I'm trying to identify reference numbers contained in strings in a column. The table looks something like this:
col1 col2
1 fgREF1234fhjdREF1235hgkjREF1236
2 hREF1237hjdfREF1238djhfhs
Need to write an SQL query that identifies the 'REF' followed by the 4 digits and returns each in its own row.
The output should look like this:
col1 ref
1 REF1234
1 REF1235
1 REF1236
2 REF1237
2 REF1238
I have tried:
select
case when substr(substr(col2, instr(col2, 'REF'), 7), 1, 1) like 'R'
then substr(col2, instr(col2, 'R'), 7) else null end ref
from table
...but this will only identify the first match in the string.
I am using Oracle SQL but ideally the solution would be able to be converted to other SQL variants.
Any help would be much appreciated!
You can use regexp_substr delimited by connect by level <= regexp_count(col2,'REF') ( the appearance time of the pattern string REF within the strings col2 )
with t(col1,col2) as
(
select 1,'fgREF1234fhjdREF1235hgkjREF1236' from dual union all
select 2,'hREF1237hjdfREF1238djhfhs' from dual
)
select col1,
regexp_substr(col2,'REF[0-9]+',1,level) as ref
from t
connect by level <= regexp_count(col2,'REF')
and prior col1 = col1
and prior sys_guid() is not null;
Demo
You can use the below code to get the desired result :-
select x.col1, explode(x.ref) as ref from (
select col1,split(trim(regexp_replace(col2,'[^REF0-9]',' ')),' ') as ref
from inp

Delimited Function in SQL to Split Data between semi-colon

I have the data below.
I'm only interested on program B. How do I change it into the table below using SQL syntax?
Below is my syntax but it doesn't give me what I want.
SELECT
SUBSTRING(Program, 0, CHARINDEX(';', Program)),
SUBSTRING(
SUBSTRING(Program, CHARINDEX(';', Program) + 1, LEN(Program)),
0,
CHARINDEX(';', SUBSTRING(Program, CHARINDEX(';', Program) + 1,
LEN(Program)))),
REVERSE(SUBSTRING(REVERSE(Program), 0, CHARINDEX(';', REVERSE(Program)))),
File_Count
FROM DataBase1
WHERE Program LIKE '%B%'
Thanks guys for your help.
Adhi
Try this:
SELECT
CASE WHEN PATINDEX('%B[0-9][0-9]%', Program)>0 THEN SUBSTRING(Program, PATINDEX('%B[0-9][0-9]%', Program) - 1, 4)
WHEN PATINDEX('%B[0-9]%', Program)>0 THEN SUBSTRING(Program, PATINDEX('%B[0-9]%', Program) - 1, 3)
ELSE '' END
FROM DataBase1
First WHEN is responsible for extracting pattern B[0-9][0-9], i.e. when B is followed by two digits, second one is for extracting B followed by one digits. Default is returning empty string, when no match is found. If you are interested in extracting pattern B followed by three digits, you need to add another when (as the first case), enter pattern B[-9][0-9][0-9] instead of B[0-9][0-9] and change last number from 4 to 5 (length of string that is extracted).
PATINDEX returns position where the match is found.
If you use PostgreSql you can try next solution.
First create temp table with data:
CREATE TABLE temp.test AS (
SELECT 'A1, B1' AS program, 1 AS file_count
UNION
SELECT 'B2', 1
UNION
SELECT 'A2, B3', 1
UNION
SELECT 'B4', 1
UNION
SELECT 'A3, B5', 2
UNION
SELECT 'B6', 2
UNION
SELECT 'B7', 2
UNION
SELECT 'B8', 1
UNION
SELECT 'B9', 1
UNION
SELECT 'C1;D1;A4;B10', 1
UNION
SELECT 'C2;D2;B11', 1
UNION
SELECT 'C3,D3,A5,B12', 1
UNION
SELECT 'C4;B14;D4;B11,B13', 1
);
I suggested that in one program cell can contains several B values (last select).
After that use regexp_matches to find all B in cell and select for each file_count value(first inner select) and after that sum by each of program:
SELECT
b_program,
sum(file_count)
FROM (
SELECT
(SELECT regexp_matches(program, 'B\d+')) [1] AS b_program,
file_count
FROM temp.test
WHERE upper(program) LIKE '%B%') bpt
GROUP BY b_program
ORDER BY b_program;

using charindex in a substring to trim a string

There is a column name from which I want to use to make a new column.
example:
name
asd_abceur1mz_a
asd_fxasdrasdusd3mz_a
asd_abceur10yz_a
asd_fxasdrasdusd15yz_a
The length of the column is not fixed so I assumed i have to use charindex to have a reference point from which I could trim.
What i want: at the end there is always z_a, and i need to place in a separate column the left part from z_a like this:
nameNew
eur1m
usd3m
eur10y
usd15y
The problem is that the number (in this example 1, 3, 10, 15) has 1 or two digits. I need to extract the information from name to nameNew.
After that i was thinking to make it easier to read and to output it like this:
eur_1m
usd_3m
eur_10y
usd_15y
I tried using a combination of substring and charindex, but so far without success.
SELECT *
, SUBSTRING(name, 1, ( CHARINDEX('z_a', NAME) - 1 )) AS nameNew
FROM myTable
This is for the first step, trimming the string, for the 2nd step (making it easier to read) I don't know how to target the digit and place an _.
Any help would be appreciated. Using sql server 2012
edit:
First of all thank you for your time and solutions. But your queries more or less even if they are working for 1 or 2 digits have the same problem. Consider this situation:
name
ab_dertEUR03EUR10YZ_A
if eur is two times in the string, then how can I eliminate this? Sorry for not includding this in my original post but i forgot that situation is possible and now that's a problem.
edit:
test your queries here, on this example:
http://www.sqlfiddle.com/#!3/21610/1
Please note that at the end it can be any combination of 1 or 2 digits and the letter y or m.
Ex: ab_rtgtEUR03EUR2YZ_A , ab_rtgtEUR03EUR2mZ_A, ab_rtgtEUR03EUR20YZ_A, ab_rtgtEUR03EUR20mZ_A
Some values for testing:
('ex_CHFCHF01CHF10YZ_A'), ('ab_rtgtEUR03EUR2YZ_A'), ('RON_asdRON2MZ_A'),
('tg_USDUSD04USD5YZ_A');
My understanding of your queries is that they perform something simillar to this (or at least they should)
ex_CHFCHF01CHF10YZ_A -> ex_CHFCHF01CHF10Y -> Y01FHC10FHCFHC -> Y01FHC -> CHF01Y -> CHF_01Y
RON_asdRON2MZ_A -> RON_asdRON2M -> M2NORdsa_ron -> M2NOR -> RON2M -> RON_2M
This works for one or two digits:
stuff(case
when name like '%[0-9][0-9]_z[_]a'
then left(right(name, 9), 6)
when name like '%[0-9]_z[_]a'
then left(right(name, 8), 5)
end, 4, 0, '_')
You can use a combination of substring , reverse and charindex.
SQL Fiddle
select substring(namenew,1,3) + '_' + substring(namenew, 4, len(namenew))
from (
select
case when name like '%[0-9][0-9]_z[_]a' then
reverse(substring(reverse(name), charindex('a_z',reverse(name)) + 3, 6))
when name like '%[0-9]_z[_]a' then
reverse(substring(reverse(name), charindex('a_z',reverse(name)) + 3, 5))
end as namenew
from myTable
) t
Try it like this:
declare #tbl TABLE(name VARCHAR(100));
insert into #tbl VALUES
('asd_abceur1mz_a')
,('asd_fxasdrasdusd3mz_a')
,('asd_abceur10yz_a')
,('asd_fxasdrasdusd15yz_a')
,('ab_dertEUR03EUR10YZ_A');
WITH CutOfThreeAtTheEnd AS
(
SELECT LEFT(name,LEN(name)-3) AS nameNew
FROM #tbl
)
,Max6CharsFromEnd AS
(
SELECT RIGHT(nameNew,6) AS nameNew
FROM CutOfThreeAtTheEnd
)
SELECT nameNew
,FirstNumber.Position
,Parts.*
,Parts.FrontPart + '_' + Parts.BackPart AS FinalString
FROM Max6CharsFromEnd
CROSS APPLY
(
SELECT MIN(x)
FROM
(
SELECT CHARINDEX('0',nameNew,1) AS x
UNION SELECT CHARINDEX('1',nameNew,1)
UNION SELECT CHARINDEX('2',nameNew,1)
UNION SELECT CHARINDEX('3',nameNew,1)
UNION SELECT CHARINDEX('4',nameNew,1)
UNION SELECT CHARINDEX('5',nameNew,1)
UNION SELECT CHARINDEX('6',nameNew,1)
UNION SELECT CHARINDEX('7',nameNew,1)
UNION SELECT CHARINDEX('8',nameNew,1)
UNION SELECT CHARINDEX('9',nameNew,1)
) AS tbl
WHERE x>0
) AS FirstNumber(Position)
CROSS APPLY(SELECT SUBSTRING(nameNew,FirstNumber.Position,1000) AS BackPart
,SUBSTRING(nameNew,FirstNumber.Position-3,3) AS FrontPart) AS Parts
this is the result:
nameNew Position BackPart FrontPart FinalString
ceur1m 5 1m eur eur_1m
dusd3m 5 3m usd usd_3m
eur10y 4 10y eur eur_10y
usd15y 4 15y usd usd_15y
EUR10Y 4 10Y EUR EUR_10Y

How do I combine 2 records with a single field into 1 row with 2 fields (Oracle 11g)?

Here's a sample data
record1: field1 = test2
record2: field1 = test3
The actual output I want is
record1: field1 = test2 | field2 = test3
I've looked around the net but can't find what I'm looking for. I can use a custom function to get it in this format but I'm trying to see if there's a way to make it work without resorting to that.
thanks a lot
You need to use pivot:
with t(id, d) as (
select 1, 'field1 = test2' from dual union all
select 2, 'field1 = test3' from dual
)
select *
from t
pivot (max (d) for id in (1, 2))
If you don't have the id field you can generate it, but you will have XML type:
with t(d) as (
select 'field1 = test2' from dual union all
select 'field1 = test3' from dual
), t1(id, d) as (
select ROW_NUMBER() OVER(ORDER BY d), d from t
)
select *
from t1
pivot xml (max (d) for id in (select id from t1))
There are several ways to approach this - google pivot rows to columns. Here is one set of answers: http://www.dba-oracle.com/t_converting_rows_columns.htm

SQL function REGEXP_SUBSTR: Regular Expression how to get the content between two characters but not include them

For these strings
RSLR_AIRL19_ID3454_T20030913091226
RSLR_AIRL19_ID3122454_T20030913091226
RSLR_AIRL19_ID34_T20030913091226
How to get the number after ID ?
Or how to get the content between two characters but not include them ?
I use this '/\_ID([^_]+)/' got matches like Array ( [0] => _ID3454 [1] => 3454 )
Is this the right way?
To extract a number after an ID, you could write a similar query.
SQL> with t1 as(
2 select 'RSLR_AIRL19_ID3454_T20030913091226' as col from dual union all
3 select 'RSLR_AIRL19_ID3122454_T20030913091226' from dual union all
4 select 'RSLR_AIRL19_ID34_T20030913091226' from dual
5 )
6 select regexp_substr(col, '^([[:alnum:]]+_){2}ID([[:digit:]]+)_([[:alnum:]]+){1}$', 1, 1, 'i', 2) as ID
7 from t1
8 ;
ID
-------------
3454
3122454
34
Or, if you want to extract digits from a first occurrence of the pattern without verifying if an entire string matches a specific format:
SQL> with t1 as(
2 select 'RSLR_AI_RL19_ID3454_T20030913091226' as col from dual union all
3 select 'RSLR_AIRL19_ID3122454_T20030913091226' from dual union all
4 select 'RSLR_AIRL19_ID34_T20030913091226' from dual
5 )
6 select regexp_substr(col, 'ID([[:digit:]]+)', 1, 1, 'i', 1) as ID
7 from t1
8 ;
ID
--------------
3454
3122454
34
With pcre & perl engines :
ID\K\w+
NOTE
\K "restart" the match.
See http://www.phpfreaks.com/blog/pcre-regex-spotlight-k (php use pcre)