TRIM in bigquery - google-bigquery

I want to apply TRIM function for my columns. But TRIM after Format function is not working. It's not trimming the spaces.
If I do it before format as below then it gives me error for datatype because the columns have other datatypes than string and byte as well.
Please tell me a solution for this.

Meantime, you can apply some extra processing on top of original query to get desired result - as in below example
select *,
trim(replace(regexp_replace(format('%t', t), r' *, *| *\)|\( *', '/'), '/NULL/', '/_/'), '/') HashColumn
from your_table t
if applied to sample data
with your_table as (
select ' 1' A, '2 ' B, null C, 4 D union all
select ' 12 ', null, '4', 5
)
output is

Consider below approach
create temp function json_extract_values(input string) returns array<string> language js as """
return Object.values(JSON.parse(input));""";
select *,
( select string_agg(trim(value), '/')
from unnest(json_extract_values(replace(to_json_string(t), ':null', ':"_"'))) value
) as HashColumn
from your_table t
if applied to dummy data as below
with your_table as (
select ' 1' A, '2 ' B, null C, 4 D union all
select ' 12 ', null, '4', 5
)
output is
which, I hope, is exactly what you are looking for

Related

Concatenating clob cloumn values in sql query

I am using this statement in my sql query to concate large clob column values but the output contains extra ","(commas) not able to figure out what is going wrong.?
SELECT RTRIM(
XMLAGG(
XMLELEMENT(
E,
CASE WHEN UNIQ_ID IN ( SELECT VAL
FROM SOME_TABLE
WHERE VAL_NM = 'SOME_TEXT' )
THEN TABLE1.COL_NAME
ELSE NULL
END,
', '
).EXTRACT('//text()')
ORDER BY TABLE1.UNIQ_ID
).GETCLOBVAL(),
','
) COMBINED_VAL
If you are asking about the trailing commas, then you are concatenating using comma then space so the trailing character is a space and not a comma.
If you are asking about adjacent separators with no value in between then when the WHEN UNIQ_ID IN ( ... ) part of your CASE statement is not matched you will have a NULL value; this is concatenated into the aggregated output and then you will find that you have two adjacent comma-space separators with no text in between.
For example:
WITH test_data ( id, value ) AS (
SELECT 1, 'a' FROM DUAL UNION ALL
SELECT 2, NULL FROM DUAL UNION ALL
SELECT 3, 'b' FROM DUAL
)
SELECT RTRIM(
XMLAGG(
XMLELEMENT(
E,
value,
', '
).EXTRACT('//text()')
ORDER BY id
).GETCLOBVAL(),
','
) AS COMBINED_VAL
FROM test_data;
Outputs:
| COMBINED_VAL |
| :----------- |
| a, , b, |
The trailing comma-space isn't trimmed as the last character is a space and the values are a then NULL then b and the NULL is represented as a zero-width substring.
db<>fiddle here
That's pretty easy:
do not aggregate rows which you don't want to get. To do that you just need to generate xmlelement only for required rows, and just return null for others.
Just put all characters you want to trim from your result into second parameter of rtrim:
SELECT RTRIM(
XMLAGG(
CASE WHEN UNIQ_ID IN ( SELECT VAL
FROM SOME_TABLE
WHERE VAL_NM = 'SOME_TEXT' )
and COL_NAME is not null
THEN XMLELEMENT(
E,
TABLE1.COL_NAME||', '
)
END
ORDER BY TABLE1.UNIQ_ID
).extract('//text()').GETCLOBVAL(),
', '
) COMBINED_VAL
from table1;
Full test case with sample data and results: https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=452c715247e8edda8735014ff2fb34f4
with
SOME_TABLE(VAL, VAL_NM) as (
select level*2, 'SOME_TEXT' from dual connect by level<=10
)
,TABLE1(UNIQ_ID, COL_NAME) as (
select level UNIQ_ID
, to_clob(level) COL_NAME
from dual
connect by level<=20
)
SELECT RTRIM(
XMLAGG(
CASE WHEN UNIQ_ID IN ( SELECT VAL
FROM SOME_TABLE
WHERE VAL_NM = 'SOME_TEXT' )
and COL_NAME is not null
THEN XMLELEMENT(
E,
TABLE1.COL_NAME||', '
)
END
ORDER BY TABLE1.UNIQ_ID
).extract('//text()').GETCLOBVAL(),
', '
) COMBINED_VAL
from TABLE1;
Results:
COMBINED_VAL
----------------------------------------
2, 4, 6, 8, 10, 12, 14, 16, 18, 20

remove extra + from text SQL

this refers to a question asked by someone else previously
previous question
my question is how do I adapt this solution so that before any function/script is ran the name and value fields are stripped of any additional + and updated so no additional + remain.
For e.g.
Name Value
A+B+C+ 1+2+3+
A++B 1++2
this should be updated to
Name Value
A+B+C 1+2+3
A+B 1+2
once this update has taken place, I can run the solution provided in the previous question.
Thanks
You need to replace ++ with + and to remove the + at the end of the string.
/* sample data */
with input(Name, Value) as (
select 'A+B+C+' ,'1+2+3+' from dual union all
select 'A++B' ,'1++2' from dual
)
/* query */
select trim('+' from regexp_replace(name, '\+{2,}', '+') ) as name,
trim('+' from regexp_replace(value, '\+{2,}', '+') ) as value
from input
If you need to update a table, you may need:
update yourTable
set name = trim('+' from regexp_replace(name, '\+{2,}', '+') ),
value= trim('+' from regexp_replace(value, '\+{2,}', '+') )
In a more compact way, without the external trim ( assuming you have no leading +):
/* sample data */
with input(Name, Value) as (
select 'A+B+C+' ,'1+2+3+' from dual union all
select 'A++B+++C+' ,'1++2+++3+' from dual union all
select 'A+B' ,'1+2' from dual
)
/* query */
select regexp_replace(name, '(\+)+(\+|$)', '\2') as name,
regexp_replace(value, '(\+)+(\+|$)', '\2') as value
from input
You could use something on the lines of:
Select substr('1+2+3+', 0, length('1+2+3+')-1) from dual ;
Select replace('1++2', '++', '+') from dual;
I'm assuming you have the output already present in a variable you can play with.
EDIT:
Here's a function that can solve the problem (You can call this function in your select clauses thereby solving the problem):
CREATE OR REPLACE Function ReplaceChars
( name_in IN varchar2 )
RETURN varchar2
IS
changed_string varchar2(20) ;
BEGIN
changed_string:=replace(name_in, '++', '+') ;
CASE WHEN substr(changed_string, -1) in ('+')
then
changed_string:=substr(changed_string,0, length(changed_string) - 1) ;
else changed_string:=changed_string ;
end CASE ;
RETURN changed_string;
END;
You can use the below:
LTRIM(RTRIM (REGEXP_REPLACE (column_name, '\+{2,}', '+'), '+'),'+')
Eg:
SELECT LTRIM(RTRIM (REGEXP_REPLACE ('+A+++B+C+++D++', '\+{2,}', '+'), '+'),'+') VALUE
FROM DUAL;
returns output: A+B+C+D
if youre working with ssms, GIVE IT A GO:::
UPDATE tablename
SET colname=
CASE colname WHEN LIKE '%++%' THEN
WHILE colname LIKE '%++%'
(REPLACE(colname,++,+))
END LOOP
WHEN LIKE '%+' THEN
SUBSTR(colname, 1, LENGTH(colname)-1)
WHEN LIKE '+%' THEN
SUBSTR(colname, 2, LENGTH(colname))
ELSE
colname
END

how to get columns have long spaces ( multiple spaces)

I have the below structure(' ' refers to empty spaces):
name description
---------------------
a yes
b ' '
c ' '
d null
I am searching for a query that give me the rows contain empty spaces, asked for the below result .
name description
---------------------
b ' '
c ' '
this query select * from tab1 where description =' '; will give me only c, in my query I have many values have long spaces.
You can user REGEXP_LIKE:
with src as (select 'a' as name,'yes' as description from dual
union all
select 'b',' ' from dual
union all
select 'c',' ' from dual
union all
select 'd',null from dual)
select * from src where regexp_like(description,'^[ ]+$'))
Edited: added regexp_like(description,'^[ ]+$') to take into account only descriptions with spaces. If there is a description in the format ' s ', ' s' or 's ' it will not be selected.
Use TRIM function to trim the spaces.
select * from tab1 where TRIM(description) IS NULL;
I have not tested it but it should work.
with this basic query:
with sample_data(name, description) as (
select 'a', 'yes' from dual union all
select 'b', ' ' from dual union all
select 'c', ' ' from dual union all
select 'd', null from dual
)
select *
from sample_data
you can pick and choose among the following where clauses to get your desired results:
where regexp_like(description,'[ ]')); -- at least one space in the string
where regexp_like(description,'[ ]{2,')); -- two or more consecutive spaces
where regexp_like(description,'^[ ]+$')); -- just spaces of any length
where regexp_like(description,'^[ ]{2,}')); -- just paces of length 2 or more
if you want any white space character (e.g. tabs, vertical tabs, non blanking spaces, etc.) you can replace the single space character class [ ] with this [[:space:]] named character class in any of the above where clauses.
Use LIKE operator
SELECT *
FROM tab1
WHERE description LIKE ' %'

Reg Expression in oracle?

I have a string like this '102/103/104/106'
Now if i pass 102 as input then output should be the next field that is 103. if 103 then output should be 104 and if 106 then output should be null(as for last field I don't have any further expression). I can do this using procedure by splitting the string into arrays and comparing. But can I do this through sql statement something like this
select '102/103/104/106' from dual where [expression 102 or 103].
Thanks!!
You can do it in pure SQL with something like this:
--convert your string into rows
with vals as (
select
substr('102/103/104/106',
instr('102/103/104/106', '/', 1, level)-3,
3
) col,
level lvl
from dual
connect by level <= length('102/103/104/106')-length(replace('102/103/104/106', '/'))+1
)
select *
from (
select col,
lead(col) over (order by lvl) next_val -- find the next value in the list
from vals
)
where col = :val;
Basically, convert your string into rows by parsing it. Then use the analytic lead to find the "next" value.
-- p_whole_string = '102/103/104/106'
-- p_prev = '102'
select
regexp_substr(p_whole_string, '(^|/)' || p_prev || '/([^/]+)', 1, 1, null, 2)
as next
from dual;
Added NVL to return last value if 106 is entered:
SELECT NVL(REGEXP_SUBSTR('102/103/104/106', '(^|/)' || '106' || '/([^/]+)', 1, 1, null, 2), REGEXP_SUBSTR('102/103/104/106', '[^/]+$')) as nxt
FROM dual
/
works for Oracle form 10 up.
SELECT
REGEXP_SUBSTR(
REGEXP_SUBSTR('102/103/104/106', '(^|/)102/[^/]+'), -- returns 102/103
'[^/]+',1,2) val -- takes second part
FROM DUAL;
with parameters looks like this:
-- p_string_to_search = '102/103/104/106'
-- p_string_to_match = '102'
SELECT
REGEXP_SUBSTR(
REGEXP_SUBSTR(p_string_to_search, '(^|/)' || p_string_to_match ||'/[^/]+'), -- returns 102/103
'[^/]+',1,2) val -- takes second part
FROM DUAL;

Create a delimitted string from a query in DB2

I am trying to create a delimitted string from the results of a query in DB2 on the iSeries (AS/400). I've done this in T-SQL, but can't find a way to do it here.
Here is my code in T-SQL. I'm looking for an equivelant in DB2.
DECLARE #a VARCHAR(1000)
SELECT #a = COALESCE(#a + ', ' + [Description], [Description])
FROM AP.Checkbooks
SELECT #a
If the descriptions in my table look like this:
Desc 1
Desc 2
Desc 3
Then it will return this:
Desc 1, Desc 2, Desc 3
Essentially you're looking for the equivalent of MySQL's GROUP_CONCAT aggregate function in DB2. According to one thread I found, you can mimic this behaviour by going through the XMLAGG function:
create table t1 (num int, color varchar(10));
insert into t1 values (1,'red'), (1,'black'), (2,'red'), (2,'yellow'), (2,'green');
select num,
substr( xmlserialize( xmlagg( xmltext( concat( ', ', color ) ) ) as varchar( 1024 ) ), 3 )
from t1
group by num;
This would return
1 red,black
2 red,yellow,green
(or should, if I'm reading things correctly)
You can do this using common table expressions (CTEs) and recursion.
with
cte1 as
(select description, row_number() over() as row_nbr from checkbooks),
cte2 (list, cnt, cnt_max) AS
(SELECT VARCHAR('', 32000), 0, count(description) FROM cte1
UNION ALL
SELECT
-- No comma before the first description
case when cte2.list = '' THEN RTRIM(CHAR(cte1.description))
else cte2.list || ', ' || RTRIM(CHAR(cte1.description)) end,
cte2.cnt + 1,
cte2.cnt_max
FROM cte1,cte2
WHERE cte1.row_nbr = cte2.cnt + 1 AND cte2.cnt < cte2.cnt_max ),
cte3 as
(select list from cte2
where cte2.cnt = cte2.cnt_max fetch first 1 row only)
select list from cte3;
I'm trying to do this in OLEDB and from what I understand you can't do this because you can't do anything fancy in SQL for OLEDB like declare variables or create a table. So I guess there is no way.
If you are running DB2 9.7 or higher, you can use LISTAGG function. Have a look here:
http://pic.dhe.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=%2Fcom.ibm.db2.luw.sql.ref.doc%2Fdoc%2Fr0058709.html