I am quite new to working with arrays in snowflake (and dbt).
I am splitting out vendor names that I have when they are filled in as join names in our front end. Now, I get them split (see the example below), but I would like to know if it is possible to split an already split array or another function I can use to split the text.
In the example below, the first 3 records are split correctly, but the following three, is not being split correctly, and this is where I would appreciate input.
The simple case statement I am using at the moment is:
,case
when upper(vendor_name) like '% AND %' then split(upper(vendor_name), ' AND ')
when vendor_name like '%&%' then split(upper(vendor_name), ' & ')
else array_construct(upper(vendor_name))
end as arr_vendor_name
You can do this in two steps:
Replace " & ", " AND ", ", " for ",".
Then split on ",".
split(
replace(replace(replace(vendor_name, ' AND ', ','), ' & ', ','), ', ', ',')
, ','
)
Bonus: You won't need the case anymore, and the array_construct goes away too.
Here is a sample of the issue:
SELECT 'True'
WHERE 'Hello ' IN ('Hello', 'Goodbye', 'Hello ')
Currently this returns 'True' because SQL ignores trailing spaces when comparing VARCHAR. In this related question, this can be solved by using LIKE, however this won't work with an IN condition.
How can I ensure that the comparison takes into account the trailing spaces, specifically when using the IN condition?
Edit:
My list of acceptable values can include items with trailing spaces. Looking to compare exact values essentially (i.e 'Hello ' won't match with 'Hello ')
Assuming that your list of acceptable values do not have trailing spaces, perhaps you could use:
SELECT 'True'
WHERE 'Hello ' IN ('Hello', 'Goodbye') AND 'Hello ' NOT LIKE '% '
You could add a non-space char to the end of your search temrs:
DECLARE #Terminator char(1) = '|';
SELECT 'True'
WHERE 'Hello ' + #Terminator IN ('Hello' + #Terminator , 'Goodbye' + #Terminator)
This will force the comparison to take into account the trailing spaces while keeping everything seargable. (I assume you want to use columns either on the left or on the right side of the IN operator)
I can think of this solution on top of my head:
SELECT 'True'
WHERE reverse('Hello ') IN (reverse('Hello'), reverse('Goodbye'))
Basically this forces to compare string using reverse function.
But Zohar's solution below is most performance driven solution.
SELECT 'True'
WHERE 'Hello '+'|' IN ('Hello'+'|', 'Goodbye'+'|')
I am trying to find a way to remove trailing and leading commas in the SELECT statement. Here is some sample data:
SELECT
GRAIN, MATERIAL, BACKING, GRITS,
REPLACE(LTRIM(RTRIM(REPLACE(PROPERTIES, ',', ' '))), ' ', ',') PROPERTIES,
SPECIAL, APPLICATION, PRODUCTTYPE
FROM PRODUCTFINDER
I tried using trim, rtrim, and ltrim but none of them changed the strings.. Idk if I was using the wrong syntax or what, but could someone help me please?
I am using SQL Server 2008.
Just another option.
This is a non-destructive approach that will eliminate any number of repeating commas and forces a final cleanup via the double pipes
For the expansion,reduction, and elimination I picked two obscure characters †‡
Example
Declare #S varchar(max) =',,,,Some,,,,,Content,,,'
Select
replace(
replace(
replace(
replace(
replace('||,' + #S + ',||', ',', '†‡'),
'‡†', ''
),
'†‡', ','
),
'||,', ''
),
',||', ''
)
Returns
Some,Content
EDIT - Removed the LTRIM()/RTRIM()
Try this:
SELECT
GRAIN, MATERIAL, BACKING, GRITS,
TRIM(',' FROM PRODUCTFINDER.PROPERTIES) AS PROPERTIES,
TRIM(',' FROM PRODUCTFINDER.SPECIAL) AS SPECIAL,
TRIM(',' FROM PRODUCTFINDER.APPLICATION) AS APPLICATION,
TRIM(',' FROM PRODUCTFINDER.PRODUCTTYPE) AS PRODUCTTYPE
FROM PRODUCTFINDER
I am not sure which columns you want to trim.
This variant of TRIM (Transact-SQL) is available since SQL-Server 2017.
If you have an earlier version of SQL-Server, do this in the Font-End (VB). This also gives you the possibility to replace multiple commas by single ones in the middle of the text.
Dim s = ",,,Abc,,,Def,Xyz,,,"
Console.WriteLine(Regex.Replace(s, ",{2,}", ",").Trim(","c))
Prints
Abc,Def,Xyz
Regex.Replace(s, ",{2,}", ",") uses the a regular expression ,{2,} to find 2 or more occurrences of commas and replaces them by one single comma. .Trim(","c) removes leading and trailing commas.
For Regex you need a
Imports System.Text.RegularExpressions
Another variant uses string split with the RemoveEmptyEntries option and then joins the parts again to form the result.
Dim s = ",,,Abc,,,Def,Xyz,,,"
Dim parts As String() = s.Split(New Char() {","c}, StringSplitOptions.RemoveEmptyEntries)
Console.WriteLine(String.Join(",", parts))
Here's one method using PATINDEX with LEFT and RIGHT.
declare #var varchar(64)= ',,,,,,,,asdf,dsf,sdfsd,asdf,,,,,,,,'
select
left(right(#var,len(#var) - patindex('%[^,]%',#var) + 1)
,len(right(#var,len(#var) - patindex('%[^,]%',#var) + 1)) - patindex('%[^,]%',reverse(right(#var,len(#var) - patindex('%[^,]%',#var) + 1))) + 1)
Just change #var to your column name.
This code strips the leading commas by searching for the first value that isn't a comma, via patindex('%[^,]%',#var) and takes everything to the RIGHT of this character. Then, we do the same thing using LEFT to remove the trailing commas.
select
Special = left(right(Special,len(Special) - patindex('%[^,]%',Special) + 1),len(right(Special,len(Special) - patindex('%[^,]%',Special) + 1)) - patindex('%[^,]%',reverse(right(Special,len(Special) - patindex('%[^,]%',Special) + 1))) + 1)
,[Application] = left(right([Application],len([Application]) - patindex('%[^,]%',[Application]) + 1),len(right([Application],len([Application]) - patindex('%[^,]%',[Application]) + 1)) - patindex('%[^,]%',reverse(right([Application],len([Application]) - patindex('%[^,]%',[Application]) + 1))) + 1)
,[ProductType] = left(right([ProductType],len([ProductType]) - patindex('%[^,]%',[ProductType]) + 1),len(right([ProductType],len([ProductType]) - patindex('%[^,]%',[ProductType]) + 1)) - patindex('%[^,]%',reverse(right([ProductType],len([ProductType]) - patindex('%[^,]%',[ProductType]) + 1))) + 1)
FROM PRODUCTFINDER
SQL Server is not ideal place for manipulating strings so trim logic should be at programming level
As far as trimming particular character is required in query, refer to below thread
Trimming any Leading or trailing characters
I need to execute a dynamic insert into a table with a variable number of columns.
Right now I'm quoting both the column names, with quote_ident, and the actual values, with quote_nullable, and then joining them with array_to_string:
for ... loop
...
cols := array_append(cols, quote_ident(column_name));
vals := array_append(vals, quote_nullable(column_value));
end loop;
execute format('insert into %s (%s) values (%s)',
target_table,
array_to_string(cols, ', ')
array_to_string(vals, ', ')
);
It's a pattern found all over the place, including on the official documentation. But it feels a bit unclean. I'd rather pass the array of values a parameter in the using clause:
execute format('insert into %s (%s) ... $1 ...',
target_table,
array_to_string(cols, ', ')
)
using vals;
Notice the using vals, which is what I'd like to achieve. But I cannot seem to be able to fill in the dots in the insert statement. Maybe some kind of select ... from ...?
More generally, how do I turn an array into a record / tuple / row type?
I'm using code very like this in production:
EXECUTE ( SELECT 'insert into sometable '
'('||string_agg(quote_ident(p.key),',') ||
') values ('|| string_agg(quote_nullable(p.value),',') || ');'
FROM each(payload) as p
);
but here payload is a hstore, not a pair of arrays.