Teradata - Create two rows from one - teradata

I need to create two rows with different keys from one using SQL. I have been unable to accomplish this.
I have one ELEMENT which needs to be separated into two.
GAAP: Should only be populated with Special Handling when it is in
the company A, B, C, or D.
Statutory: Should ALWAYS equal what is in the parent (Special Handling)
My current code does not work because of the case statement. If it is in A,B,C,D then it is assigned correctly, but the second one does not. It only picks up the other companies.
SELECT
CASE
WHEN (AB.DATA_ELEMENT_BUSINESS_NME = 'Special Handling' AND AB.UNIT_COMPANY_NME IN ('A','B','C','D')) THEN 'GAAP Special Handling'
WHEN AB.DATA_ELEMENT_BUSINESS_NME = 'Special Handling' THEN 'Statutory Special Handling'
ELSE AB.DATA_ELEMENT_BUSINESS_NME
END AS DATA_ELEMENT_BUSINESS_NME,
sum(AB.DATA_ELEMENT_AMT) as DATA_ELEMENT_AMT
FROM
Any suggestions?
Update
Data IN: Special Handling -3727286.720000
Data OUT: GAAP Special Handling -3727286.720000
Statutory Special Handling -3727286.720000

For a single input record, you are expecting two output records. The basic idea you are missing here is that how much ever logic you put in there, a single query like this is going to give you a single output record for a single input record.
What you need is a union:
SELECT
'GAAP Special Handling' AS DATA_ELEMENT_BUSINESS_NME,
sum(AB.DATA_ELEMENT_AMT) as DATA_ELEMENT_AMT
FROM YOUR_TABLE
WHERE
AB.DATA_ELEMENT_BUSINESS_NME = 'Special Handling' AND
AB.UNIT_COMPANY_NME IN ('A','B','C','D')
UNION ALL
SELECT
CASE WHEN AB.DATA_ELEMENT_BUSINESS_NME = 'Special Handling'
THEN 'Statutory Special Handling'
ELSE AB.DATA_ELEMENT_BUSINESS_NME
END AS DATA_ELEMENT_BUSINESS_NME,
sum(AB.DATA_ELEMENT_AMT) as DATA_ELEMENT_AMT
FROM YOUR_TABLE

Related

Is it possible to invert the order of "LIKE" operation?

My database has a table with columns genus, species, and inatcode. inatcode is blank for every row it hasn't been manually added to. I imported a new table that contains all the codes and want to create an Update query that copies them all to the corresponding rows of the first table. However, because the species column of my first table has additional strings, the match is not perfect and many rows were not updated. table.a.species might look like :
x bimundorum
vesicula (sexgen)
sinuata breviloba
And I want it to match these values in table.b.species:
bimundorum
vesicula
sinuata
I know to use table.a.species LIKE '%table.b.species%' when b is a substring of a, but this is the opposite case and just flipping (shown below) doesn't seem to work. Is there another way to accomplish this in SQLite? The differences between a and b are heterogeneous, but there are only a few cases and I could potentially do multiple queries to account for each.
"UPDATE table.a SET inatcode = table.b.inatcode
FROM table.b
WHERE table.b.genus = table.a.genus
AND table.a.species LIKE '%table.b.species%' "
I am working with SQLite through the DBI package in R, and could make all of this happen in R and reinsert instead. But it seems like this I should be able to do in SQLite.
The modified formatting posted here does what I wanted; I just needed to use the || to concatenate the values and the % operator to make the LIKE function behave as I wanted it to.
"UPDATE table.a SET inatcode = table.b.inatcode
FROM table.b
WHERE table.b.genus = table.a.genus
AND table.a.species LIKE '%' || table.b.species || '%'
AND table.b.species != '' "

How to convert a number with decimal values to a float in PL/SQL?

The issue is that I need to insert this number into json, and because the number contains a comma, json becomes invalid. A float would work because it contains a period not a comma.
I have tried using replace(v_decimalNumber,',','.') and it kind of works, except that the json property is converted to a string. I need it to remain some type of a numerical value.
How can this be achieved?
I am using Oracle 11g.
You just need to_number() function.
select to_number(replace('1,2', ',', '.')) float_nr from dual;
Result:
FLOAT_NR
1.2
Note that if your number has .0 like 1.0, the function will remove it and leave it only 1
The data type of v_decimalNumber is some type of character format as it can contain commas (,). Your contention is that it contains a number once the commas are removed. However there is NO SUCH THING until that contention has been validated since being character I can put any character(s) I want into it subject to any length restriction. As an example a spreadsheet column that should contain numeric data. However, it that doesn't apply users will often put N/A into telling themselves that it doesn't apply. Oracle will happily load this into your v_decimalNumber. (And that's 1 of many many ways non-numeric data can get into your column.) So before attempting to process as a numeric value you must validate it is in fact valid numeric data. The following demonstrates one such way.
with some_numbers (n) as
( select '123,4456,789.00' from dual union all
select '987654321.00' from dual union all
select '1928374655' from dual union all
select '1.2' from dual union all
select '.1' from dual union all
select '1..1' from dual union all
select 'N/A' from dual
)
, rx as (select '^[0-9]*\.?[0-9]*$' regexp from dual)
select n
, case when regexp_like(replace(n,',',null), regexp)
then to_number(replace(n,',',null))
else null
end Num_value
, case when regexp_like(replace(n,',',null), regexp)
then null
else 'Not valid number'
end msg
from some_numbers,rx ;
Take away: Never trust a character type column to contain specific data requirements except random characters. Always validate then put the data into the appropriately defined columns.

How can I dynamically change the where conditions of a for each loop?

I have a table of records that has two logical flags, holdn and holdl. I want to loop through this table with 3 different criteria.
Either flag is TRUE - We want to see everything that is on hold
Flag holdl is TRUE - We only want see items that are on hold for this one reason
Flag holdn is TRUE - We only want to see items that are on hold for this other reason.
I cannot figure out how to dynamically change the for each loop based on this. What I have tried so far is to set the value of a variable based on these conditions and then use the content of the variable as one of the where parameters. This does not work as Progress complains that there is a data mismatch. The variable is a string, the flags are logical, so that does make sense. See sample code below. This is a snippet of the actual code with the the table name changed. The which-hold, order-from, etc variables are defined and set in a different module which calls this one.
DEFINE VARIABLE which-hold# AS CHARACTER FORMAT "x(30)" NO-UNDO.
CASE which-hold:
WHEN "B" THEN which-hold# = "(widget.holdn or widget.holdl)".
WHEN "L" THEN which-hold# = "widget.holdl".
WHEN "N" THEN which-hold# = "widget.holdn".
END CASE.
for each widget where which-hold# and
widget.order-no >= order-from and widget.order-no <= order-thru and
widget.line-no >= line-from and widget.line-no <= line-thru and
widget.joint-no >= joint-from and widget.joint-no <= joint-thru
no-lock:
A bunch of code to make a nice report with the retrieved records...
end.
Self taught Progress programmer here, who has inherited a huge, poorly documented application. Please be gentle.
If you would prefer not to deal with handles a semi-dynamic approach is also possible:
define variable i as integer no-undo.
define query q for customer.
do while true:
update i.
case i:
when 0 then quit.
when 1 then open query q for each customer no-lock where custNum >= 1000.
when 2 then open query q for each customer no-lock where state = "nh".
otherwise open query q for each customer no-lock where name begins "u".
end.
do while true with frame a:
get next q.
if not available customer then leave.
display custNum name state with frame a 10 down.
down with frame a.
end.
close query q.
end.
What you want is actually a dynamic query. I'll get to it at the end, but first I'd like to explain why you won't be able to try and substitute the field name in the which-hold# variable: because the query is evaluated at compile time. And this is what it reads (supposing which-hold# has a value of widget.holdn
FOR EACH widget where "widget-holdn" (...)
And that does not evaluate to TRUE or FALSE. So what, you ask? Well, that is the key here. Every condition needs to evaluate to true or false, so you'd be more in luck if you try
for each widget where (if widget-hold# = 'widget.holdn' then widget.holdn = true else TRUE) (...)
Again, notice the condition will exist if widget-hold# has the value I want, otherwise it doesn't filter on this at all.
So you can just code the way I showed (for each of the conditions you have) and it should work fine.
BUT let me suggest a dynamic query instead.
You need to have:
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
CREATE QUERY hQuery.
hQuery:SET-BUFFERS(BUFFER widget:HANDLE).
hQuery:QUERY-PREPARE('<THIS IS THE CORE>').
hQuery:QUERY-OPEN().
DO WHILE hQuery:GET-NEXT():
A bunch of code to make a nice report with the retrieved records...
END.
So in the core you have a string that corresponds to your for each the way you want it to look. So it should be for example (store this in a variable, or assemble it inside the query prepare, it doesn't matter):
'FOR EACH widget NO-LOCK WHERE ' +
(if which-hold = 'B' then 'widget.holdn = true and widget.holdl = true'
else if which-hold = 'L' then 'widget-holdl = true'
else /* N */ 'widget-holdn = true').
Remember I said your query is evaluated at compile time? Well, just so you know, dynamic queries on the other end are evaluated at run time, so be prepared for errors to pop up only when you run. Another thing I should mention is dynamic queries are slower than static ones, so please evaluate and choose your poison :)
This should be what you need. Please let me know if it's helpful or any questions remain.

Use case statement for parameter for column name in sql where clause

I have been looking all day for a solution that works for my situation. I have found some things that are very similar but don't work for my situation, I tried them.
Here is the scenario; I have two table base and partdetails. I have an asp website (internal ONLY) that has drop down lists to select the parameters for a SQL query that fills a data grid view.
My problem is this, I need to be able, based on the drop down list boxes on the page, assign the column name that the criteria that is entered to be searched for.
Here is the query that I am trying to define: (This one returns 0 rows)
sqlCmd.CommandText = ("Select ba.referenceid, ba.partnum, pd.width, pd.length, CONVERT(varchar(12), pd.dateentered, 101) As [dateentered], ba.partqty, ba.status, ba.material From tbl_dlbase ba Join tbl_partdetails pd On ba.referenceid = pd.referenceid Where Case #field1 When 'part #' Then 'ba.partnum' When 'Spacing' Then 'pd.spacing' When 'Surface' Then 'pd.surface' When 'Height' Then 'pd.height' When 'Thickness' Then 'pd.thickness' End Like '%' + #criteria1 + '%'")
sqlCmd.Parameters.AddWithValue("#field1", ddlSc1.SelectedItem.Text)
sqlCmd.Parameters.AddWithValue("#criteria1", txbCriteria1.Text)
This is the latest version of the SQL statement that I have tried. I need to be able to set the field/column name based on the selection from the drop down list ddlsc1 on the asp page.
I have also been trying the queries in Studio manager to see if maybe I have fat fingered something but it also returns 0 rows so I know something is wrong with the query.
So how can I set the column name field using a parameter for the name. I know this is a huge security concern with SQL injection but this is an internal only site, and more importantly my boss said he wants it done with variables.
I don't really see a problem with this other than you have single quotes around your THEN values. Does this fix it?
SELECT ba.referenceid
,ba.partnum
,pd.width
,pd.length
,CONVERT(VARCHAR(12), pd.dateentered, 101) AS [dateentered]
,ba.partqty
,ba.STATUS
,ba.material
FROM tbl_dlbase ba
JOIN tbl_partdetails pd ON ba.referenceid = pd.referenceid
WHERE CASE #field1
WHEN 'part #'
THEN ba.partnum
WHEN 'Spacing'
THEN pd.spacing
WHEN 'Surface'
THEN pd.surface
WHEN 'Height'
THEN pd.height
WHEN 'Thickness'
THEN pd.thickness
END LIKE '%' + #criteria1 + '%'

SQLite: How to select part of string?

There is table column containing file names: image1.jpg, image12.png, script.php, .htaccess,...
I need to select the file extentions only. I would prefer to do that way:
SELECT DISTINCT SUBSTR(column,INSTR('.',column)+1) FROM table
but INSTR isn't supported in my version of SQLite.
Is there way to realize it without using INSTR function?
below is the query (Tested and verified)
for selecting the file extentions only. Your filename can contain any number of . charenters - still it will work
select distinct replace(column_name, rtrim(column_name,
replace(column_name, '.', '' ) ), '') from table_name;
column_name is the name of column where you have the file names(filenames can have multiple .'s
table_name is the name of your table
Try the ltrim(X, Y) function, thats what the doc says:
The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X.
List all the alphabet as the second argument, something like
SELECT ltrim(column, "abcd...xyz1234567890") From T
that should remove all the characters from left up until .. If you need the extension without the dot then use SUBSTR on it. Of course this means that filenames may not contain more that one dot.
But I think it is way easier and safer to extract the extension in the code which executes the query.

Resources