im trying to validate a column using postgresql
where values in the column are (0000-ASZAS) four numerical values-five alphbets
SELECT invoice_number,
CASE
WHEN invoice_number = '[0-9][0-9][0-9][0-9]-[A-Z][A-Z][A-Z][A-Z][A-Z]'
THEN 'valid'
ELSE 'invalid'
END
from invoices;
also tried LIKE instead of =
sorry wrong column customer_id with alpha numeric values
invoice_number is numeric. thank you for the correction
Try ~ or similar_to. See functions-matching
WHEN invoice_number ~ '[0-9][0-9][0-9][0-9]-[A-Z][A-Z][A-Z][A-Z][A-Z]'
You may use the ~ POSIX regex operator:
SELECT invoice_number,
CASE WHEN invoice_number ~ '^[0-9]{4}-[A-Z]{5}$'
THEN 'valid'
ELSE 'invalid' END
FROM invoices;
I'm cleaning a data and want to return 0 rows so it doesn't crowd the results so this is what I did...
SELECT customer_id FROM invoices
WHERE customer_id !~ '[0-9][0-9][0-9][0-9]-[A-Z][A-Z][A-Z][A-Z][A-Z]';
w/c gives me exactly what I want. Would this be as strong/valid for cleaning compared to using like or = ?
Related
In TSQL, the string in the database record is 'A/A/A' or 'A/B/A' (examples). I want to parse the string and for the first instance return '1'; in the 2nd instance, return '2'. That is, if all the values between the separators are the same, return a value; otherwise return another value. What is the best way to do this?
A bit blind answer:
Read the whole value in a variable. Read the first value part in another:
declare #entire nvarchar(max), #single nvarchar(max)
select/set #entire=....
set #single=left(#entire,charindex('/',#entire)-1)
Compare entire with #single replicated after removing slashes:
set #entire=replace(#entire,'/','')
select case when replicate(#single,len(#entire)/len(#single))=#entire
then 1 else 0 end as [What you want]
Something like this should work:
SELECT
x.*,
CASE
WHEN N > 1 THEN 0
ELSE 1
END Result
FROM (
SELECT
t.Column1,
t.Column2,
t.Column3,
t.SomeColumn,
COUNT(DISTINCT s.value) N
FROM dbo.YourTable t
OUTER APPLY STRING_SPLIT(t.SomeColumn,'/') s
GROUP BY
t.Column1,
t.Column2,
t.Column3,
t.SomeColumn
) x
;
Based on your simple example (no edge cases accounted for) the following should work for you:
select string, iif(replace(s,v,'')='',1,0) as Result
from t
cross apply (
values(left(string,charindex('/', string)-1),(replace(string,'/','')))
)s(v,s);
Example Fiddle
Is there a way to check if a character varying type column contains only digits or null values with Postgresql?
Maybe something like (this syntax is incorrect):
SELECT *
FROM mytable
ORDER BY
CASE WHEN mycol ~ '^[0-9\.]+$' THEN 1 ELSE 0 END
LIMIT 1
I'm expecting TRUE or FALSE as final result for the whole column.
If you want to to know if the values in all rows are digits, you can use
select not exists (select *
from mytable
where not (mycol ~ '^[0-9\.]+$'))
Online example
To get Nulls use COALESCE(mycol, 1) -- will return 1 if the value in mycol is NULL.
For checking numerics you could use regex LIKE'^[0-9]*' it wont detect decimal dots (dont know if your data have decimals)
BR!
In DB2 SQL, is it possible to SET a variable with the contents of a returned field in the SELECT statement, to use multiple times for calculated fields and criteria further along in the same SELECT statement?
The purpose is to shrink and streamline the code, by doing a calculation once at the beginning and using it multiple times later on...including the HAVING, WHERE, and ORDER BY.
To be honest, I'm not sure this is possible in any version of SQL, much less DB2.
This is on an IBM iSeries 8202 with DB2 SQL v6, which unfortunately is not a candidate for upgrade at this time. This is a very old & messy database, which I have no control over. I must regularly include "cleanup functions" in my SQL.
To to clarify the question, note the following pseudocode. Actual working code follows further below.
DECLARE smnum INTEGER --Not sure if this is correct.
SELECT
-- This is where I'm not sure what to do.
SET CAST((CASE WHEN %smnum%='' THEN '0' ELSE %smnum% END) AS INTEGER) INTO smnum,
%smnum% AS sm,
invdat,
invno,
daqty,
dapric,
dacost,
(dapric-dacost)*daqty AS profit
FROM
saleshistory
WHERE
%smNum% = 30
ORDER BY
%smnum%
Below is my actual working SQL. When adjusted for 2017 or 2016, it can return >10K rows, depending on the salesperson. The complete table has >22M rows.
That buttload of CASE((CAST... function is what I wish to replace with a variable. This is not the only example of this. If I can make it work, I have many other queries that could benefit from the technique.
SELECT
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER) AS DASM,
DAIDAT,
DAINV# AS DAINV,
DALIN# AS DALIN,
CAST(TRIM(DAITEM) AS INTEGER) AS DAITEM,
TRIM(DABSW) AS DABSW,
TRIM(DAPCLS) AS DAPCLS,
DAQTY,
DAPRIC,
DAICOS,
DADPAL,
(DAPRIC-DAICOS+DADPAL)*DAQTY AS PROFIT
FROM
VIPDTAB.DAILYV
WHERE
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER)=30 AND
TRIM(DABSW)='B' AND
DAIDAT BETWEEN (YEAR(CURDATE())*10000) AND (((YEAR(CURDATE())+1)*10000)-1) AND
CAST(TRIM(DACOMP) AS INTEGER)=1
ORDER BY
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER),
DAIDAT,
DAINV#,
DALIN#
Just use a subquery or CTE. I can't figure out the actual logic you want, but the structure looks like this:
select . . .
from (select d.*,
(CASE . . . END) as calc_field
from VIPDTAB.DAILYV d
) d
No variable declaration is needed.
Here is what your SQL would look like with the sub-query that Gordon suggested:
SELECT
DASM,
DAIDAT,
DAINV# AS DAINV,
DALIN# AS DALIN,
CAST(DAITEM AS INTEGER) AS DAITEM,
TRIM(DABSW) AS DABSW,
TRIM(DAPCLS) AS DAPCLS,
DAQTY,
DAPRIC,
DAICOS,
DADPAL,
(DAPRIC-DAICOS+DADPAL)*DAQTY AS PROFIT
FROM
(SELECT
D.*,
CAST((CASE WHEN D.DASM#='' THEN '0' ELSE D.DASM# END) AS INTEGER) AS DASM
FROM VIPDTAB.DAILYV D
) D
WHERE
DASM=30 AND
TRIM(DABSW)='B' AND
DAIDAT BETWEEN (YEAR(CURDATE())*10000) AND (((YEAR(CURDATE())+1)*10000)-1) AND
CAST(DACOMP AS INTEGER)=1
ORDER BY
DASM,
DAIDAT,
DAINV#,
DALIN#
Notice that I removed a lot of the trim() functions, and you could likely remove the rest. The way IBM resolves the Varchar vs. Char comparison thing is by ignoring trailing blanks. So trim(anything) = '' is the same as anything = ''. And since cast(' 123 ' as integer) = 123, I have removed trims from within the cast functions as well. In addition trim(dabsw) = 'B' is the same as dabsw = 'B' as long as the 'B' is the first character in dabsw. So you could even remove that trim if all you are concerned with is trailing blanks.
Here are some additional notes based on comments. The above paragraph is not talking about auto-trim. Fixed length fields will always return as fixed length fields, the trailing blanks will remain. But in comparisons and expressions where trailing blanks are unimportant, or even a hindrance, they are ignored. In expressions where trailing blanks are important, like concatenation, the trailing blanks are not ignored. Another thing, trim() removes both leading and trailing blanks. If you are using trim() to read a fixed length character field into a Varchar, then rtrim() is likely the better choice as it only removes the trailing blanks.
Also, I didn't go through your fields to make sure I got everything you need, I just used * in the sub-query. For performance, it would be best to only return the fields you need. So if you replace D.* with an actual field list, you can remove the correlation name in the from clause of the sub-query. But, the sub-query itself still needs a correlation clause.
My verification was done using IBM i v7.1.
You can encapsalate the case statement in a view. I even have the fancy profit calc in there for you to order by profit. Now the biggest issue you have is the CCSID on the view for calculated columns but that's another question.
create or replace view VIPDTAB.DAILYVQ as
SELECT
CAST((CASE WHEN TRIM(DASM#)='' THEN '0' ELSE TRIM(DASM#) END) AS INTEGER) AS DASM,
DAIDAT,
DAINV# AS DAINV,
DALIN# AS DALIN,
CAST(TRIM(DAITEM) AS INTEGER) AS DAITEM,
TRIM(DABSW) AS DABSW,
TRIM(DAPCLS) AS DAPCLS,
DAQTY,
DAPRIC,
DAICOS,
DADPAL,
(DAPRIC-DAICOS+DADPAL)*DAQTY AS PROFIT
FROM
VIPDTAB.DAILYV
now you can
select dasm, count(*) from vipdtab.dailyvq where dasm = 0 group by dasm order by dasm
or
select * from vipdtab.dailyvq order by profit desc
I have a table named `test' which has following structure.
category key value
name real_name:Brad,nick_name:Brady,name_type:small NOVALUE
other description cool
But I want to break key column into multiple rows based on , delimiter and value after : delimiter should be a part of value column where value is equal to NOVALUE. So output should look like:
category key value
name real_name Brad
name nick_name Brady
name name_type small
other description cool
How to write sql query for this . I am using postgresql.
Any help ? Thanks in advance.
You can use string_to_array and unnest to do this:
select ts.category,
split_part(key_value, ':', 1) as key,
split_part(key_value, ':', 2) as value
from test ts
cross join lateral unnest(string_to_array(ts.key, ',')) as t (key_value)
where ts.value = 'NOVALUE'
union all
select category,
key,
value
from test
where value <> 'NOVALUE';
SQLFiddle example: http://sqlfiddle.com/#!15/6f1e6/1
select category,
split_part(key_value, ':', 1) as key,
case when value = 'NOVALUE' then split_part(key_value, ':', 2) else value end
from test
cross join lateral unnest(string_to_array(key, ',')) as t (key_value)
How to get valid value from the following query
SELECT Answer FROM table
WHERE values LIKE '%[^0-9]%'
Basically I want the data can deal for
28,000 (valid)
$20000 (valid)
Annual Amount (invalid)
? (invalid)
28.00 (valid)
Thanks
SELECT Answer
FROM table
WHERE
ISNUMERIC(values)
OR (
SUBSTRING(values, 1, 1) = '$'
AND ISNUMERIC(RIGHT(values, LEN(values) - 1)))
you could do something like:
select replace(replace(values, '$', ''), ',', '') as number from table
where dbo.RegexMatch(values, ^\$?(\d+|(\d{1,3}(,\d{3})+))(\.\d+)?$')
tweak the regex to match any conditions you need...