We have different tables which have been accidentially filled in various fields with null values which are now causing problems when trying to display them.
I know how I could replace them one column by one, but I would like to know if there is an easy way to replace all null values in all columns. I did not come up with any possible solution.
Calculating 30 tables with about 80 columns in average this would take a while creating the SQL(s).
Any suggestions how to simplify this task?
We use DB2 V9, in case there is a function for it or similar
Thanks in advance
Xavjer
You can use the catalog tables to get the name from the columns you want to modify (all if you want)
select 'update ' || trim(tabschema) || '.' || trim(tabname)
|| ' set ' || trim(colname) || ' = '' '''
|| ' where ' || trim(colname) || ' is NULL;'
from syscat.columns
where tabschema not like 'SYS%'
and XXX YYYY ;
(Not tested, but it should be something like this)
This query will generate a set of lines that you will execute (copy/paste) or you cat put in a file and then
db2 -tvf file.sql | db2 +p -tv
The last where condition is your own condition to filter the catalog. If you want to filter for more criteria, you can use the syscat.tables view.
I'm not familiar with the db2 luw tools, but you should be able to generate at least a create table script from the existing table. With a little but of find and replace magic you could change the create into an alter table that includes the not null with default clause.
Related
SELECT Distinct 'DROP TABLE IF EXISTS deleted.' || LISTAGG("table_name",',') || ';' FROM svv_all_columns WHERE schema_name = 'sn' and database_name='db';
ERROR:One or more of the used functions must be applied on at least one user created tables. Examples of user table only functions are LISTAGG, MEDIAN, PERCENTILE_CONT, et
SELECT Distinct 'DROP TABLE IF EXISTS deleted.' || LISTAGG("table_name",',') || ';' FROM svv_all_columns WHERE schema_name = 'sn' and database_name='db';
It concatanetes all table names in one drop statement
That's what LISTAGG() does - it aggregates strings from multiple rows together. It can work in conjunction with GROUP BY to combine strings from only within a group.
It sounds like you just want to have individual table names concatenated with the static text. Like this:
SELECT Distinct 'DROP TABLE IF EXISTS deleted.' || "table_name" || ';' FROM svv_all_columns WHERE schema_name = 'sn' and database_name='db'
Which will put each DROP statement on its own row. If instead you want one block of text you can use LISTAGG() over the combined strings like this:
SELECT LISTAGG('DROP TABLE IF EXISTS deleted.' || "table_name" || ';',',') FROM svv_all_columns WHERE schema_name = 'sn' and database_name='db';
Now DISTINCT doesn't make sense in this case as there is only one string. This could result in extra DROP statement so if you really need the minimum number of DROP statements AND for all of this to be in 1 string:
WITH drops AS (
SELECT Distinct 'DROP TABLE IF EXISTS deleted.' || "table_name" || ';' AS statement
FROM svv_all_columns WHERE schema_name = 'sn' and database_name='db'
)
SELECT LISTAGG(statement,' ')
FROM drops;
Note that I took the ',' out as the text separator as this doesn't make sense in a block of SQL.
Hopefully these examples will give you enough info to understand the basics of LISTAGG().
Objective:
I would like to make a measure and a calculated column (for the sake of knowing how to write both) using an IF statement but can't get it to work
Query:
Column =
IF(
Refund[orderTotalPrice]=Refund[amount] && Refund[status] = 'refund' ,
Refund[amount] - Refund[total_tax]- Refund[shipping_price],
Refund[amount]
)
the expression refers to multiple columns multiple columns cannot be converted to a scalar value
When creating an if statement in a calculated column you can only have one comparison statement. If you want 2, like in your example, you need to use the AND function. Also make sure you use " instead of ' for string comparison.
I tested this calculated column and this worked for me:
Column = if(
AND(Refund[orderPriceTotal]=Refund[amount],Refund[status]="Refund"),
Refund[amount] - Refund[total_tax] - Refund[shipping price],
Refund[amount]
)
In your case, I do not think there is an easy solution to solve this in a measure. Why would you want to build it as a measure?
I want to delete some tables and wrote this procedure:
set serveroutput on
declare
type namearray is table of varchar2(50);
total integer;
name namearray;
begin
--select statement here ..., please see below
total :=name.count;
dbms_output_line(total);
for i in 1 .. total loop
dbms_output.put_line(name(i));
-- execute immediate 'drop table ' || name(i) || ' purge';
End loop;
end;
/
The idea is to drop all tables with table name having pattern like this:
ERROR_REPORT[2 digit][3 Capital characters][10 digits]
example: ERROR_REPORT16MAY2014122748
However, I am not able to come up with the correct regexp. Below are my select statements and results:
select table_name bulk collect into name from user_tables where regexp_like(table_name, '^ERROR_REPORT[0-9{2}A-Z{3}0-9{10}]');
The results included all the table names I needed plus ERROR_REPORT311AUG20111111111. This should not be showing up in the result.
The follow select statement showed the same result, which meant the A-Z{3} had no effect on the regexp.
select table_name bulk collect into name from user_tables where regexp_like(table_name, '^ERROR_REPORT[0-9{2}0-9{10}]');
My question is what would be the correct regexp, and what's wrong with mine?
Thanks,
Alex
Correct regex is
'^ERROR_REPORT[0-9]{2}[A-Z]{3}[0-9]{10}'
I think this regex should work:
^ERROR_REPORT[0-9]{2}[A-Z]{3}[0-9]{10}
However, please check the regex101 link. I've assumed that you need 2 digits after ERROR_REPORT but your example name shows 3.
I have an sqlite database which has number sequences with random separators. For example
_id data
0 123-45/678>90
1 11*11-22-333
2 4-4-5-67891
I want to be able to query the database "intelligently" with and without the separators. For example, both these queries returning _id=0
SELECT _id FROM myTable WHERE data LIKE '%123-45%'
SELECT _id FROM myTable WHERE data LIKE '%12345%'
The 1st query works as is, but the 2nd query is the problem. Because the separators appear randomly in the database there are too many combinations to loop through in the search term.
I could create two columns, one with separators and one without, running each query against each column, but the database is huge so I want to avoid this if possible.
Is there some way to structure the 2nd query to achieve this as is ? Something like a regex on each row during the query ? Pseudo code
SELECT _id
FROM myTable
WHERE REPLACEALL(data,'(?<=\\d)[-/>*](?=\\d)','') LIKE '%12345%'
Ok this is far from being nice, but you could straightforwardly nest the REPLACE function. Example:
SELECT _id FROM myTable
WHERE REPLACE(..... REPLACE(REPLACE(data,'-',''),'_',''), .... '<all other separators>','') = '12345'
When using this in practice (--not that I would recommend it, but at least its simple), you surely might wrap it inside a function.
EDIT: for a small doc on the REPLACE function, see here, for example.
If I get it right, is this what you want?
SELECT _id
FROM myTable
WHERE Replace(Replace(Replace(data, '?', ''), '/', ''), '-', '') LIKE '%12345%'
I have to prepare strings to be suitable for queries because these strings will be used in the queries as field values. if they contain a ' etc the sql query fails to execute.
I therefore want to replace ' with '' I have seen the code to find and replace a substring with a substring. but I guess the problem is a little tricky because replacing string also contains two single quotes '' replacing one quote ' so when I have to find the next occurance it would encounter a ' which was intentionally replaced.
I am using Sql lite C api and the example query might look like this
select * from persons where name = 'John' D'oe'
Since John Doe contain a ' the query will fail , so I want all occurances of ' in the name to replaced with ''
Any ideas how you guys prepares your field values in query to be used in sql ??? may be it's a basic thing but I am not too smart in C/C++.
your help would be very helpful
Use queries with arguments instead of replacing stuff, which could lead to several problems (like SQL injection vulnerabilities).
MySQL example:
sql::Connection *con = ...;
string query = "SELECT * FROM TABLE WHERE ID = ?";
sql::PreparedStatement *prep_stmt = con->prepareStatement(query);
prep_stmt->setInt(1, 1); // Replace first argument with 1
prep_stmt->execute();
This will execute SELECT * FROM TABLE WHERE ID = 1.
EDIT: more info for SQLite prepared statements here and here.
It depends on the SQL Library you are using. Some of them will have the concept of a PreparedStatement, which you will use question marks in place of the variables, then when you set those variables on the statement, it will internally ensure that you cannot inject sql commands.