How to find substrings in SQL (Postgres) - sql

Let's say I have a column called 'code' in my database table containing string data types.
I want a query that will return all rows with a 'code' value that is a substring of a given search string, with the added condition that the substring appears at the end of the search string.
For example, if the search string is '12345', the query should return all rows with a 'code' value of:
12345
2345
345
45
5

Simply use like operator:
SELECT * from yourtable
where '12345' like '%' || Code

You can use a recursive CTE:
with recursive cte as (
select code
from yourtable t
union all
select substring(code, 2)
from cte
where code > ''
)
select *
from cte;
Or, you could use a lateral join and generate_series():
select substring(code, i)
from t cross join lateral
generate_series(1, length(code)) gs(i)

Related

How to convert one row text from a result of a query into a string that can be used in another query in PostgreSQL?

I have a query like this:
select value from some_table_name where key='some_key'
The result is 1 row only. It is a text with commas
apple,banana,orange
How can I use that result in this below query?
SELECT unnest(
string_to_array('use above text from query in here', ',')
) AS parts;
You can use the unnest directly in the FROM clause:
select u.*
from some_table_name t
cross join unnest(string_to_array(t.value, ',')) as u(val)
where t.key='some_key';
Or with a current version of Postgres:
select u.*
from some_table_name t
cross join string_to_table(t.value, ',') as u(val)
where t.key='some_key'

Is there a SQL function to expand table?

I vaguely remember there being a function that does this, but I think I may be going crazy.
Say I have a datatable, call it table1. It has three columns: column1, column2, column3. The query
SELECT * FROM table1
returns all rows/columns from table1. Isn't there some type of EXPAND function that allows me to duplicate that result? For example, if I want to duplicate everything from the SELECT * FROM table1 query three times, I can do something like EXPAND(3) ?
In BigQuery, I would recommend a CROSS JOIN:
SELECT t1.*
FROM table1 CROSS JOIN
(SELECT 1 as n UNION ALL SELECT 2 UNION ALL SELECT 3) n;
This can get cumbersome for lots of copies, but you can simplify this by generating the numbers:
SELECT t1.*
FROM table1 CROSS JOIN
UNNEST(GENERATE_ARRAY(1, 3)) n
This creates an array with three elements and unnests it into rows.
In both these cases, you can include n in the SELECT to distinguish the copies.
Below is for BigQuery Standard SQL
I think below is close enough to what "got you crazy" o)
#standardSQL
SELECT copy.*
FROM `project.dataset.tabel1` t, UNNEST(FN.EXPAND(t, 3)) copy
To be able to do so, you can leverage recently announced support for persistent standard SQL UDFs, namely - you need to create FN.EXPAND() function as in below example (note: you need to have FN dataset in your project - or use existing dataset in which case you should use YOUR_DATASET.EXPAND() reference
#standardSQL
CREATE FUNCTION FN.EXPAND(s ANY TYPE, dups INT64) AS (
ARRAY (
SELECT s FROM UNNEST(GENERATE_ARRAY(1, dups))
)
);
Finally, if you don't want to create persistent UDF - you can use temp UDF as in below example
#standardSQL
CREATE TEMP FUNCTION EXPAND(s ANY TYPE, dups INT64) AS ( ARRAY(
SELECT s FROM UNNEST(GENERATE_ARRAY(1, dups))
));
SELECT copy.*
FROM `project.dataset.tabel1` t, UNNEST(EXPAND(t, 3)) copy
if you want a cartesian product (all the combination on a row ) you could use
SELECT a.*, b.*, c.*
FROM table1 a
CROSS JOIN table1 b
CROSS JOIN table1 c
if you want the same rows repeated you can use UNION ALL
SELECT *
FROM table1
UNION ALL
SELECT *
FROM table1
UNION ALL
SELECT *
FROM table1
Use union all
Select * from table1
Union all
Select * from table1
Union all
Select * from table1
Union all
Select * from table1
For reuse purposes can embed this code in a procedure like
Create Procedure
expandTable(tablename
varchar2(50))
As
Select * from table1
Union all
Select * from table1
Union all
Select * from table1
Union all
Select * from table1
End
/

use distinct and order by in STRING_AGG function

I am trying the string_agg a column while at the same time ordering the column and only show unique values. Consider the following demo. IS there a syntax issue or is this simply not possible with the method I am using?
SELECT STRING_AGG(DISTINCT foo.a::TEXT,',' ORDER BY foo.a DESC)
FROM (
SELECT 1 As a
UNION ALL
SELECT 1
UNION ALL
SELECT 1
UNION ALL
SELECT 2
) AS foo
[2019-11-22 13:29:32] [42P10] ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list
[2019-11-22 13:29:32] Position: 53
The error message is quite clear. The expression that you use in the ORDER BY clause must also appear in the aggregated part.
You could do:
SELECT STRING_AGG(DISTINCT foo.a::TEXT, ',' ORDER BY foo.a::TEXT DESC)
FROM (
SELECT 1 As a
UNION ALL SELECT 1
UNION ALL SELECT 1
UNION ALL SELECT 2
) AS foo
Demo on DB Fiddle
While this will work, the problem with this solution is that it will order numbers as strings, that do not have the same ordering rules. String wise, 10 is less than 2.
Another option is to use arrays: first, ARRAY_AGG() can be used to aggregate the numbers (with proper, numeric ordering), then you can turn it to a comma-separated list of strings with ARRAY_TO_STRING().
SELECT ARRAY_TO_STRING(ARRAY_AGG(DISTINCT a ORDER BY a DESC), ',')
FROM (
SELECT 1 As a
UNION ALL SELECT 1
UNION ALL SELECT 1
UNION ALL SELECT 2
) AS foo
Demo on DB Fiddle

Convert from single column to multiple Column in sql Server

i have tried with below code. but i didnt get ouput as per multiple column.
select Name=stuff((select ','+
name from Input t1 WHERE t1.Name=t2.name for xml path('')),1,9,''),NAME
=stuff((select ','+
name from Input t1 WHERE t1.Name=t2.name for xml path('')),1,1,'')FROM
Input T2
GROUP BY NAME
I have separated the character and numeric parts of the given string in CTE and used a simple group by and sum clause on that.
;With CTE
As
(
Select
Left(Names, 1) As String,
SUBSTRING(Names, 2, Len(Names) - 1) As Number
From SeparateColumns
)
Select
String,
Sum(Cast(Number As Int)) As SumOfDigits
From CTE
Group By String
Order By String;
Assuming you will have single character in your column, the following code works
CREATE TABLE #TEMP_SPLIT
(VALUE VARCHAR(25))
INSERT INTO #TEMP_SPLIT
SELECT 'A10'
UNION
SELECT 'B20'
UNION
SELECT 'A30'
UNION
SELECT 'B40'
UNION
SELECT 'A10'
UNION
SELECT 'C1'
SELECT c, sum(tot)
FROM
(
SELECT SUBSTRING(VALUE,1,1) c ,CONVERT(FLOAT,SUBSTRING(VALUE,2,LEN (VALUE)-1)) Tot
FROM #TEMP_SPLIT
)T
GROUP BY C
DROP TABLE #TEMP_SPLIT
If the names column is always in the specified format, then use LEFT function to extract the character part and RIGHT function to extract the digits part and use these two in the sub-query and use GROUP BY clause and SUM function.
Query
select t.col_a as [string character],
sum(cast(t.col_b as int)) as [sum of digits] from(
select left(names, 1) as col_a,
right(names, len(names) - 1) as col_b
from [your_table_name]
) t
group by t.col_a;
Find a example here
You could use PATINDEX() with SUBSTRING() function if names always in this specified format
select A.CHAR [Strings], SUM(CAST(A.VALUE AS INT)) [Sum] from
(
SELECT SUBSTRING(Name, 1, PATINDEX('%[^A-Z]%', Name)-1) [CHAR], SUBSTRING(Name, PATINDEX('%[0-9]%', Name), len(Name)) [VALUE] FROM <table>
) a GROUP BY A.CHAR
Here's simple solution using subquery and group by clause:
select [StringChar], SUM([Number]) from (
select SUBSTRING(Names, 1, 1) as [StringChar],
convert(int, SUBSTRING(Names, 2, LEN(Names))) as [Number]
from [Input]
) as a group by [StringChar]

Select from table with multiple values

My query is
SELECT *
FROM tblalumni_member
WHERE username IN ( SELECT *
FROM Split('ramesh,sagar,pravin', ',') )
AND Is_Approved = 1
and username field contains multiple values separated by comma. Like ramesh,sachin,pravin.
It should give all rows if any of get matched in selected result.
Can you please help me?
In case of SQL Server perhaps something like
SELECT *
FROM tblalumni_member m
WHERE Is_Approved = 1 AND
EXISTS(
SELECT * FROM Split(m.username, ',')
INTERSECT
SELECT * FROM Split('ramesh,sagar,pravin', ',')
)