Correct statement for UNION ALL with three or more selects - db2

I have the following situation:
I have a script consisting of 6 selects joined by "UNION ALL".
From the CLP DB2 console, this script fails. Curiously, each query independently work, and even come to work if grouped in pairs. However, when I try with three or more, it fails.
So, my question is: is there is a limit for more that one UNION ALL?
My environment is:
Client. DB2 Connect server 10.1
zOS 390 (no idea what is the DB2 version on that side)
AIX 7.1
The query is like this (but three times )
SELECT
,'GG'
,varchar(right( '000000000000000' || rtrim(ltrim(eeee.zzzz)), 15), 15)
,substr(char(right('**********'||char(left(replace(eeee.yyyy,' ','*')||'**********',10),10),10),10),1,7)
,eeee.kkkkk
,eeee.hhhhhh
,CASE WHEN hhhhhh='A5 ' THEN 'ARS' WHEN hhhhhh='A6 ' THEN 'AUD' WHEN hhhhhh='B5 ' THEN 'BRL' WHEN hhhhhh='U1 ' THEN 'GBP' WHEN hhhhhh='B9 ' THEN 'BND' WHEN hhhhhh='B6 ' THEN 'BNG' WHEN hhhhhh='C1 ' THEN 'CAD' WHEN hhhhhh='C3 ' THEN 'CLP' WHEN hhhhhh='C4 ' THEN 'CNY' WHEN hhhhhh='C5 ' THEN 'COP' WHEN hhhhhh='C7 ' THEN 'CRC' WHEN hhhhhh='L5 ' THEN 'HRK' WHEN hhhhhh='C9 ' THEN 'CYP' WHEN hhhhhh='X0 ' THEN 'CZK' WHEN hhhhhh='D0 ' THEN 'DKK' WHEN hhhhhh='D1 ' THEN 'DOP' WHEN hhhhhh='U0 ' THEN 'EGP' WHEN hhhhhh='E3 ' THEN 'EUR' WHEN hhhhhh='G5 ' THEN 'GTQ' WHEN hhhhhh='H0 ' THEN 'HTG' WHEN hhhhhh='H3 ' THEN 'HUF' WHEN hhhhhh='I1 ' THEN 'INR' WHEN hhhhhh='I2 ' THEN 'IDR' WHEN hhhhhh='K2 ' THEN 'WON' WHEN hhhhhh='L6 ' THEN 'LVL' WHEN hhhhhh='L7 ' THEN 'LTL' WHEN hhhhhh='M2 ' THEN 'MYR' WHEN hhhhhh='M6 ' THEN 'MXN' WHEN hhhhhh='I8 ' THEN 'ILS' WHEN hhhhhh='N2 ' THEN 'NZD' WHEN hhhhhh='N4 ' THEN 'NIO' WHEN hhhhhh='N6 ' THEN 'NOK' WHEN hhhhhh='T4 ' THEN 'XPF' WHEN hhhhhh='P0 ' THEN 'PKR' WHEN hhhhhh='P1 ' THEN 'PAB' WHEN hhhhhh='P3 ' THEN 'PEN' WHEN hhhhhh='P4 ' THEN 'PHP' WHEN hhhhhh='P5 ' THEN 'PLN' WHEN hhhhhh='R2 ' THEN 'RON' WHEN hhhhhh='U3 ' THEN 'RUB' WHEN hhhhhh='S0 ' THEN 'SAR' WHEN hhhhhh='R6 ' THEN 'RSD' WHEN hhhhhh='S2 ' THEN 'SGD' WHEN hhhhhh='K5 ' THEN 'SKK' WHEN hhhhhh='S4 ' THEN 'ZAR' WHEN hhhhhh='C2 ' THEN 'LKR' WHEN hhhhhh='S8 ' THEN 'SEK' WHEN hhhhhh='S9 ' THEN 'CHF' WHEN hhhhhh='T2 ' THEN 'THB' WHEN hhhhhh='T6 ' THEN 'TRL' WHEN hhhhhh='U4 ' THEN 'USD' WHEN hhhhhh='U6 ' THEN 'UAH' WHEN hhhhhh='U5 ' THEN 'AED' WHEN hhhhhh='U2 ' THEN 'UYU' WHEN hhhhhh='V0 ' THEN 'VEB' WHEN hhhhhh='V1 ' THEN 'VND' WHEN hhhhhh='J1 ' THEN 'JPY' ELSE '###' END
, case when eeee.FCRCIDF='Y' then 1 else 0 end
,
CASE
WHEN SUBSTR(eeee.yyyy,7,1) = 'X' THEN 'X'
WHEN SUBSTR(eeee.yyyy,4,2) = 'O' THEN 'O'
WHEN SUBSTR(eeee.yyyy,4,2) = 'C' THEN 'C'
WHEN SUBSTR(eeee.yyyy,4,2) = 'R' THEN 'R'
WHEN eeee.lll = 'F' THEN 'F'
WHEN eeee.ppp <> '' THEN 'D'
WHEN eeee.rrr = 0 THEN '0'
WHEN eeee.rrr <> eeee.ACINTOT THEN 'P'
WHEN eeee.rrr = eeee.ACINTOT THEN '1'
ELSE '*'
END
,1
,eeee.DCINISS
,0
from (SELECT ori.*,oric.tttt FROM www.SK1V01_CUSTOMER ori left OUTER JOIN www.SK1V01A_CUSTCUF oric
ON ori.bbbb=oric.bbbb and ori.ICUSCNO=oric.ICUSCNO ) as aaaa
,www.SK1V02_OPENBILL eeee,www.SK1V41_OPENBILL kkkk
where aaaa.bbbb=eeee.bbbb
and aaaa.cagllic=eeee.cagllic
and aaaa.icuscno=eeee.icuscno

Without the entire statement its pretty hard to determine exact reasons. An given that just one portion is so long & poorly formatted, I'm not sure we'd want to dig through it all. But I can suggest a few approaches that may help resolve your problem.
Simplest part first. In practically any computer language, well formatted code helps you see the structure of what's going on. It may also help you spot the differences between your queries. (Perhaps you know this, & your code merely lost its formatting when you tried to post it.)
When trying to UNION multiple complex queries, it's not uncommon to have column inconsistencies among the queries. You might have missing or extra columns, or columns out of order. But it's possible some of your column expressions are evaluating to different types. You might want to cast() those expressions, or use type conversion functions, just to be sure.
There's so much going on here. Try testing with a version where you comment out large chunks of code, same on each major subquery, until you find which part is causing the problem.
You have a ridiculously long CASE expression on hhhhhh. Why don't you put these value pairs into a lookup table that you can join to.
Try using a module approach, just as you should when writing a large program. You could create a view for each of the major queries, then UNION them together. (Some developers use layers of views like layers of modular code).
Metadata about your views is available in the database catalog views. This means you could write a query to compare the attributes of the columns in your set of union views.

Related

DB2 TRANSLATE for Question Mark in Data

I have a statement on DB2 using the TRANSLATE function:
,TRANSLATE( FIELD1, ' ', x'042021222324282A3638FF') FIELD1A
How to I modify the statement for a question mark character in data
Thank you.
ihope that i understood youright. You want to replace a '?' by ' ' is that true? in this case translate works like this:
VALUES translate('sdnfojs?sdmf', ' ', x'6F'),
translate('sdnfojs?sdmf', ' ', '?');
--result: 'sdnfojs sdmf'

T-SQL stored procedure to get data from any table on the server for CSV export (SQL Server 2016)

Answered / Solved.
Long story short, I need a stored procedure that would get the data from a few different views and put it into a .CSV file. Easy enough, but me being me, I decided to write something that could get the data from any table one could potentially desire. I decided to go with 2 procedures in the end:
Loop through a table with all the parameters (catalog, schema, table name, export path/file name etc. etc.) and feed it to 2nd stored procedure (in theory it should make it easier to manage in future, if/when different data needs to be exported). This one is fairly straightforward and doesn't cause any issues.
Pick up the column names (which was surprisingly easy - below in case it helps anyone)
select #SQL = 'insert into Temp_Export_Headers ' +
'select COLUMN_NAME ' +
'from [' + #loc_Source_Database + '].information_schema.columns ' +
'where table_name = ''' + #loc_Source_Table + ''''
and
select #Headers = coalesce(#Headers + ',', '') + convert(varchar, Column_Name)
from Temp_Export_Headers
After that, I want to dump all the data from "actual" table into temp one, which in itself is easy enough, but that's where things start to go downhill for me.
select #SQL =
'drop table if exists TempData ' +
'select * ' +
'into TempData ' +
'from [' + #loc_Source_Database + '].' + #loc_Source_Schema + '.' + #loc_Source_Table + ' with (nolock) '
Select * is just temporary, will probably replace it with a variable later on, for now it can live in this state on dev.
Now I want to loop through TempData and insert things I want (everything at the moment, will add some finesse and where clauses in near future) and put it into yet another temp table that holds all the stuff for actual CSV export.
Is there any way to add a self incrementing column to my TempData without having to look for and get rid of the original PK / Identity? (Different tables will have different values / names for those, making it a bit of a nightmare for someone with my knowledge / experience to loop through in a sensible manner, so I'd just like a simple column starting with 1 and ending with whatever last row number is)
#ShubhamPandey 's answer was exactly what I was after, code below is a product of my tired mind on the verge of madness (It does, however, work)
select #SQL =
'alter table TempData ' +
'add Uni_Count int'
select #SQL2 =
'declare #UniCount int ' +
'select #UniCount = 0 ' +
'update tempdata with (rowlock) ' +
'set #UniCount = Uni_Count = #UniCount + 1'
Both versions execute quicker than select * into without any other manipulation. Something I cannot yet comprehend.
Is there a better / more sensible way of doing this? (My reasoning with the loop - there will potentially be a lot of data for some of the tables / views, with most of them executed daily, plan was to export everything on Sat/Sun when system isn't that busy, and have daily "updates" going from last highest unique id to current.)
Looping was a horrible idea. To illustrate just how bad it was:
Looping through 10k rows meant execution time of 1m 21s.
Not looping through 500k rows resulted in execution time of 56s.
Since you are doing a table creation while insertion, you can always go forward with a statement like:
select #SQL =
'drop table if exists TempData ' +
'select ROW_NUMBER() OVER (<some column name>) AS [Id], * ' +
'into TempData ' +
'from [' + #loc_Source_Database + '].' + #loc_Source_Schema + '.' + #loc_Source_Table + ' with (nolock) '
This would create an auto-incrementing index for you in the TempData table

UPDATE table via join in SQL

I am trying to normalize my tables to make the db more efficient.
To do this I have removed several columns from a table that I was updating several columns on.
Here is the original query when all the columns were in the table:
UPDATE myActDataBaselDataTable
set [Correct Arrears 2]=(case when [Maturity Date]='' then 0 else datediff(d,convert(datetime,#DataDate, 102),convert(datetime,[Maturity Date],102)) end)
from myActDataBaselDataTable
Now I have removed [Maturity Date] from the table myActDataBaselDataTable and it's necessary to retrieve that column from the base reference table ACTData, where it is called Mat.
In my table myActDataBaselDataTable the Account number field is a concatenation of 3 fields in ACTData, thus
myActDataBaselDataTable.[Account No]=ac.[Unit] + ' ' + ac.[ACNo] + ' ' + ac.[Suffix]
(where ac is the alias for ACTData)
So, having looked at the answers given elsewhere on SO (such as 1604091: update-a-table-using-join-in-sql-server), I tried to modify this particular update statement as below, but I cannot get it right:
UPDATE myActDataBaselDataTable
set dt.[Correct Arrears 2]=(
case when ac.[Mat]=''
then 0
else datediff(d,convert(datetime,'2014-04-30', 102),convert(datetime,ac.[Mat],102))
end)
from ACTData ac
inner join myActDataBaselDataTable dt
ON dt.[Account No]=ac.[Unit] + ' ' + ac.[ACNo] + ' ' + ac.[Suffix]
I either get an Incorrect syntax near 'From' error, or The multi-part identifier "dt.Correct Arrears 2" could not be bound.
I'd be grateful for any guidance on how to get this right, or suugestiopns about how to do it better.
thanks
EDIT:
BTW, when I run the below as a SELECT it returns data with no errors:
select case when [ac].[Mat]=''
then 0
else datediff(d,convert(datetime,'2014-04-30', 102),convert(datetime,[ac].[Mat],102))
end
from ACTData ac
inner join myActDataBaselDataTable dt
ON dt.[Account No]=ac.[Unit] + ' ' + ac.[ACNo] + ' ' + ac.[Suffix]
In a join update, update the alias
update dt
What is confusing is that in later versions of SQL you don't need to use the alias in the update line

Return first and last words in a person name - postgres

I have a list of names and I want to separate the first and last words in a person's name.
I was trying to use the "trim" function without success.
Can someone explain how could I do it?
table:
Names
Mary Johnson Angel Smith
Dinah Robertson Donald
Paul Blank Power Silver
Then I want to have as a result:
Names
Mary Smith
Dinah Donald
Paul Silver
Thanks,
You can do it simply with regular expressions, like:
substring(trim(name) FROM '^([^ ]+)') || ' ' || substring(trim(name) FROM '([^ ]+)$')
Of course it would only work you are 100% there is always supplied at least a first and a last name. I'm not 100% sure it is the case for everybody in the World. For instance: would that work for names in Chinese? I'm not sure and I avoid doing any assumption about people names. The best is to simply ask the user two fields, one for the "name" and another for "How would you like to be called?".
Another approach, which takes advantage of Postgres string processing built-in functions:
SELECT split_part(name, ' ', 1) as first_token,
split_part(name, ' ', array_length(regexp_split_to_array(name, ' '), 1)) as last_token
FROM mytable
Here's how I extracted full names from emails with a dot in them, eg Jeremy.Thompson#abc.com
SELECT split_part(email, '.', 1) || ' ' || replace(split_part(email, '.', 2), '#abc','')
FROM people
Result:
Jeremy | Thompson
You can easily replace the dot with a space:
SELECT split_part(email, ' ', 1) || ' ' || replace(split_part(email, ' ', 2), '#abc','')
FROM people

PGSQL - Joining two tables on complicated condition

I got stuck during database migration on PostgreSQL and need your help.
I have two tables that I need to join: drzewa_mateczne.migracja (data I need to migrate) and ibl_as.t_adres_lesny (dictionary I need to join with migracja).
I need to join them on replace(drzewa_mateczne.migracja.adresy_lesne, ' ', '') = replace(ibl_as.t_adres_lesny.adres, ' ', ''). However my data is not very regular, so I want to join it on first good match with the dictionary.
I've created the following query:
select
count(*)
from
drzewa_mateczne.migracja a
where
length(a.adresy_lesne) > 0
and replace(a.adresy_lesne, ' ', '') = (select substr(replace(al.adres, ' ', ''), 1, length(replace(a.adresy_lesne, ' ', ''))) from ibl_as.t_adres_lesny al limit 1)
The query doesn't return any rows.
It does successfully join empty rows if ran without
length(a.adresy_lesne) > 0
The two following queries return rows (as expected):
select replace(adres, ' ', '')
from ibl_as.t_adres_lesny
where substr(replace(adres, ' ', ''), 1, 16) = '16-15-1-13-180-c'
limit 1
select replace(adresy_lesne, ' ', ''), length(replace(adresy_lesne, ' ', ''))
from drzewa_mateczne.migracja
where replace(adresy_lesne, ' ', '') = '16-15-1-13-180-c'
I'm suspecting that there might be a problem in sub-query inside the 'where' clause in my query. If you guys could help me resolve this issue, or at least point me in the right direction, I'd be very greatful.
Thanks in advance,
Jan
You can largely simplify to:
SELECT count(*)
FROM drzewa_mateczne.migracja a
WHERE a.adresy_lesne <> ''
AND EXISTS (
SELECT 1 FROM ibl_as.t_adres_lesny al
WHERE replace(al.adres, ' ', '')
LIKE (replace(a.adresy_lesne, ' ', '') || '%')
)
a.adresy_lesne <> '' does the same as length(a.adresy_lesne) > 0, just faster.
Replace the correlated subquery with an EXISTS semi-join (to get only one match per row).
Replace the complex string construction with a simple LIKE expression.
More information on pattern matching and index support in these related answers:
PostgreSQL LIKE query performance variations
Difference between LIKE and ~ in Postgres
speeding up wildcard text lookups
What you're basically telling the database to do is to get you the count of rows from drzewa_mateczne.migracja that have a non-empty adresy_lesne field that is a prefix of the adres field of a semi-random ibl_as.t_adres_lesny row...
Lose the "limit 1" in the subquery and substitute the "=" with "in" and see if that is what you wanted...