Is DECLARE what I should be using in order to reference a created field within the same program - tsql

I'm trying to create a new field and then later on in my program reference that new field within a case statement, but I can't seem to get the syntax right - my error message says there's an error near the '='.
Here's my code:
declare #source_sys_obligation_id varchar(40);
if facility_utilization in ('F')
set source_sys_obligation_id = source_sys_facility_id
else set source_sys_obligation_id = source_sys_utilization_num;
select
source_sys_utilization_num
,source_sys_id
,facility_utilization
,case when source_sys_id in ('AFSEAST','AFSLSAL','DFBDOM','ACBS')
then right('000000000000000' + substring(source_sys_obligation_id,6,10),16)
when source_sys_id in ('MLSTLEND')
then right('000000000000000' + left(source_sys_obligation_id,15),16)
else '' end as No
from BridgeUnderwrite.dbo.t_sag_pimsc1
where source_sys_id in ('AFSEAST','AFSLSAL','DFBDOM','ACBS','MLSTLEND')
order by source_sys_id
;

The error is in reference to the set statements. They should look like:
if facility_utilization in ('F')
set #source_sys_obligation_id = source_sys_facility_id
else
set #source_sys_obligation_id = source_sys_utilization_num;
That ought to do it :) . . . however, source_sys_facility_id and source_sys_utilization_num are most likely going to be your next issues . . . are they variables (or perhaps parameters passed in) as well?

The '#' is part of the name. All T-SQL variable names or procedure parameters have to begin with this character (I assume the reason is so they are easy to discern from table and column names). So you probably need to say set #source_sys_obligation_id ... instead of set source_sys_obligation_id ....

What you want and what you can have are not the same! You cannot create a field in a select stament and then reference it in the same select statment in a case. Your code makes no sense at all and indcates a severe lack of understanding of how variables work.
declare #source_sys_obligation_id varchar(40);
if facility_utilization in ('F')
set source_sys_obligation_id = source_sys_facility_id
else set source_sys_obligation_id = source_sys_utilization_num;
This does not add columns to a select nor would it even populate anything even adding the #sign as some others have suggested because you do not have a select here. Further a variable can only have one value, not a different value per record. So scrap this whole approach. What you really need is a derived table or a CTE. You could also simply embed the first case in the second case. Something like this might get waht you are asking for:
SELECT a.source_sys_utilization_num
,a.source_sys_id
,a.facility_utilization
,CASE WHEN a.source_sys_id in ('AFSEAST','AFSLSAL','DFBDOM','ACBS')
THEN RIGHT('000000000000000' + SUBSTRING(a.source_sys_obligation_id,6,10),16)
WHEN a.source_sys_id in ('MLSTLEND')
THEN RIGHT('000000000000000' + LEFT(a.source_sys_obligation_id,15),16)
ELSE '' END AS [No]
FROM
(SELECT
source_sys_utilization_num
,source_sys_id
,facility_utilization
,CASE WHEN facility_utilization = 'F' THEN source_sys_facility_id
ELSE source_sys_utilization_num END AS source_sys_obligation_id
FROM BridgeUnderwrite.dbo.t_sag_pimsc1
WHERE source_sys_id in ('AFSEAST','AFSLSAL','DFBDOM','ACBS','MLSTLEND')) a
ORDER BY source_sys_id
Too busy to write the other versions. Maybe someone else will supply.

Related

How to use CASE clause (DB2) to display values from a different table?

I'm working in a bank so I had to adjust the column names and information in the query to fit the external web, so if there're any weird mistakes know it is somewhat fine.
I'm trying to use the CASE clause to display data from a different table, I know this is a workaround but due to certain circumstances I'm obligated to use it, plus it is becoming interesting to figure out if there's an actual solution.
The error I'm receiving for the following query is:
"ERROR [21000] [IBM][CLI Driver][DB2] SQL0811N The result of a scalar
fullselect, SELECT INTO statement, or VALUES INTO statement is more
than one row."
select bank_num, branch_num, account_num, client_id,
CASE
WHEN exists(
select *
from bank.services BS
where ACCS.client_id= BS.sifrur_lakoach
)
THEN (select username from bank.services BS where BS.client_id = ACCS.client_id)
ELSE 'NONE'
END username_new
from bank.accounts accs
where bank_num = 431 and branch_num = 170
EDIT:
AFAIK we're using DB2 v9.7:
DSN11015 - DB21085I Instance "DB2" uses "64" bits and DB2 code release "SQL09075" with
level identifier "08060107".
Informational tokens are "DB2 v9.7.500.702", "s111017", "IP23287", and Fix Pack "5".
Use listagg function to include all results.
select bank_num, branch_num, account_num, client_id,
CASE
WHEN exists(
select *
from bank.services BS
where ACCS.client_id= BS.sifrur_lakoach
)
THEN (select LISTAGG(username, ', ') from bank.services BS
where BS.client_id = ACCS.client_id)
ELSE 'NONE'
END username_new
from bank.accounts accs
where bank_num = 431 and branch_num = 170

SELECT with substring in ON clause?

I have the following select statement in ABAP:
SELECT munic~mandt VREFER BIS AB ZZELECDATE ZZCERTDATE CONSYEAR ZDIMO ZZONE_M ZZONE_T USAGE_M USAGE_T M2MC M2MT M2RET EXEMPTMCMT EXEMPRET CHARGEMCMT
INTO corresponding fields of table GT_INSTMUNIC_F
FROM ZCI00_INSTMUNIC AS MUNIC
INNER JOIN EVER AS EV on
MUNIC~POD = EV~VREFER(9).
"where EV~BSTATUS = '14' or EV~BSTATUS = '32'.
My problem with the above statement is that does not recognize the substring/offset operation on the 'ON' clause. If i remove the '(9) then
it recognizes the field, otherwise it gives error:
Field ev~refer is unknown. It is neither in one of the specified tables
nor defined by a "DATA" statement. I have also tried doing something similar in the 'Where' clause, receiving a similar error:
LOOP AT gt_instmunic.
clear wa_gt_instmunic_f.
wa_gt_instmunic_f-mandt = gt_instmunic-mandt.
wa_gt_instmunic_f-bis = gt_instmunic-bis.
wa_gt_instmunic_f-ab = gt_instmunic-ab.
wa_gt_instmunic_f-zzelecdate = gt_instmunic-zzelecdate.
wa_gt_instmunic_f-ZZCERTDATE = gt_instmunic-ZZCERTDATE.
wa_gt_instmunic_f-CONSYEAR = gt_instmunic-CONSYEAR.
wa_gt_instmunic_f-ZDIMO = gt_instmunic-ZDIMO.
wa_gt_instmunic_f-ZZONE_M = gt_instmunic-ZZONE_M.
wa_gt_instmunic_f-ZZONE_T = gt_instmunic-ZZONE_T.
wa_gt_instmunic_f-USAGE_M = gt_instmunic-USAGE_M.
wa_gt_instmunic_f-USAGE_T = gt_instmunic-USAGE_T.
temp_pod = gt_instmunic-pod.
SELECT vrefer
FROM ever
INTO wa_gt_instmunic_f-vrefer
WHERE ( vrefer(9) LIKE temp_pod ). " PROBLEM WITH SUBSTRING
"AND ( BSTATUS = '14' OR BSTATUS = '32' ).
ENDSELECT.
WRITE: / sy-dbcnt.
WRITE: / 'wa is: ', wa_gt_instmunic_f.
WRITE: / 'wa-ever is: ', wa_gt_instmunic_f-vrefer.
APPEND wa_gt_instmunic_f TO gt_instmunic_f.
WRITE: / wa_gt_instmunic_f-vrefer.
ENDLOOP.
itab_size = lines( gt_instmunic_f ).
WRITE: / 'Internal table populated with', itab_size, ' lines'.
The basic task i want to implement is to modify a specific field on one table,
pulling values from another. They have a common field ( pod = vrefer(9) ). Thanks in advance for your time.
If you are on a late enough NetWeaver version, it works on 7.51, you can use the OpenSQL function LEFT or SUBSTRING. Your query would look something like:
SELECT munic~mandt VREFER BIS AB ZZELECDATE ZZCERTDATE CONSYEAR ZDIMO ZZONE_M ZZONE_T USAGE_M USAGE_T M2MC M2MT M2RET EXEMPTMCMT EXEMPRET CHARGEMCMT
FROM ZCI00_INSTMUNIC AS MUNIC
INNER JOIN ever AS ev
ON MUNIC~POD EQ LEFT( EV~VREFER, 9 )
INTO corresponding fields of table GT_INSTMUNIC_F.
Note that the INTO clause needs to move to the end of the command as well.
field(9) is a subset operation that is processed by the ABAP environment and can not be translated into a database-level SQL statement (at least not at the moment, but I'd be surprised if it ever will be). Your best bet is either to select the datasets separately and merge them manually (if both are approximately equally large) or pre-select one and use a FAE/IN clause.
They have a common field ( pod = vrefer(9) )
This is a wrong assumption, because they both are not fields, but a field an other thing.
If you really need to do that task through SQL, I'll suggest you to check native SQL sentences like SUBSTRING and check if you can manage to use them within an EXEC_SQL or (better) the CL_SQL* classes.

Need help understanding quotation marks in a SQL string to be passed to linked server.

I need to build a SQL statement to be submitted on a linked server. The statement makes use of #parameters and case statements which contain quotation marks.
I found this Microsoft article 'How to pass a variable', which seemed ideal, however I am not able to get everything going. It seems that the linked server is not enabled for the final and neatest suggestion of calling Sp_executesql, so I have been trying the first two examples.
To start with, here is a cut down example of my SQL statement on its own:
SELECT *,
CASE WHEN FLDA = 'ABC' THEN 'DEF' ELSE 'ABC' END AS COL1
FROM MYTABLE
WHERE FLDB = #PARM
1, I can get the query to work when excluding the CASE statement:
DECLARE #TSQL NVARCHAR(4000), #PARM NVARCHAR(10)
SET #PARM = 'ABC'
SET #TSQL = 'SELECT * FROM OPENQUERY(MYLINKEDSERVER, ''
SELECT *
FROM MYTABLE
WHERE FLDA = '''''+#PARM+''''''')'
EXEC (#TSQL)
However I don't understand why I require 5 quotes before #PARM and then 7(!) after it? When coding SQL statements in a string in previous languages just 2 quotations together acted as a single. So why 5 and 7?
2, I can't get the SQL to work at all when attempting to add the CASE statement. I have tried all combinations of 2,3,4 quotations but to no avail: Do I again need a certain amount of opening quotes and then a different amount of closing quotes?
DECLARE #TSQL NVARCHAR(4000), #PARM NVARCHAR(10)
SET #PARM = 'ABC'
SET #TSQL = 'SELECT * FROM OPENQUERY(MYLINKEDSERVER, ''
SELECT *,
CASE WHEN FLDA = ''ABC'' THEN ''DEF'' ELSE ''ABC'' END AS COL1
FROM MYTABLE
WHERE FLDA = '''''+#PARM+''''''')'
EXEC (#TSQL)
Any help greatly appreciated!
Cheers
Mark
my first question was why do I need 5 and 7 quotes, so there was no error message there, but I get the point that I could have listed some of the errors seen when I was getting the incorrect number of quotes.
However the tip to use Print was very useful, so thank you all for that!
So it transpires that I do indeed require a pair of
quotes where a single quote is required. However, as I am creating a SQL string within a string, I need to double that again. So I first need to end my string with a single quote and then add 4 quotes to create the double quote required to proceed the variable - hence 5. And likewise, I need 4 quotes to get a pair of quotes following the variable, another pair of quotes for the quote to end the statement and then a final one to wrap around the end bracket of the OPENQUERY command....I hope that sort of reads correct!
So:
WHERE FLDA = '''''+#PARM+''''''')'
Printed as:
WHERE FLDA = ''ABC''')
And for my CASE statement, I required 4 set of quotes, to equate to 2. So:
CASE WHEN FLDA = ''''ABC'''' THEN ''''DEF'''' ELSE ''''ABC'''' END AS COL1
Printed as:
CASE WHEN FLDA = ''ABC'' THEN ''DEF'' ELSE ''ABC'' END AS COL1

Data tweaking code runs fine when executed directly - but never stops when used in trigger

I have written some code to ensure that items on an order are all numbered (the "position number" or "item number" has been introduced only recently and we did not want to go and change all related code - as it is "asthetics only" and has no functional impact.)
So, the idea is to go and check for an records that jave an itemno of NULL or 0 - and then compute one and assign it. When executing this code in a query window, it works fine. When putting it into an AFTER INSERT-trigger, it loops forever.
So what is wrong here?
/****** Objekt: Trigger [SetzePosNr] Skriptdatum: 02/28/2010 20:06:29 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [SetzePosNr]
ON [dbo].[bestellpos]
AFTER INSERT
AS
BEGIN
DECLARE #idb int
DECLARE #idp int
DECLARE #pnr int
SELECT #idp=id,#idb=id_bestellungen FROM bestellpos WHERE posnr IS NULL OR posnr=0
WHILE #idp IS NOT NULL
BEGIN
SELECT #pnr = 1+max(posnr) FROM bestellpos WHERE id_bestellungen = #idb
print( 'idp=' + str(#idp) + ', idb=' + str(#idb) + ', posnr=' + str(#pnr))
UPDATE bestellpos SET posnr=#pnr WHERE id=#idp
SELECT #idp=id,#idb=id_bestellungen FROM bestellpos WHERE posnr IS NULL OR posnr=0
END
END
Aaaargh - just found the problem: the 3d line (from the end, the SELECT-statement) does not assign the variables when there result of the WHERE is NULL. So "set #idp=null" before that statement has fixed the problem!
Not sure whhy I assumed a problem between direct execution and triggering of these statements, seems I picked the wrong test-cases :(

DESCENDING/ASCENDING Parameter to a stored procedure

I have the following SP
CREATE PROCEDURE GetAllHouses
set #webRegionID = 2
set #sortBy = 'case_no'
set #sortDirection = 'ASC'
AS
BEGIN
Select
tbl_houses.*
from tbl_houses
where
postal in (select zipcode from crm_zipcodes where web_region_id = #webRegionID)
ORDER BY
CASE UPPER(#sortBy)
when 'CASE_NO' then case_no
when 'AREA' then area
when 'FURNISHED' then furnished
when 'TYPE' then [type]
when 'SQUAREFEETS' then squarefeets
when 'BEDROOMS' then bedrooms
when 'LIVINGROOMS' then livingrooms
when 'BATHROOMS' then bathrooms
when 'LEASE_FROM' then lease_from
when 'RENT' then rent
else case_no
END
END
GO
Now everything in that SP works but I want to be able to choose whether I want to sort ASCENDING or DESCENDING.
I really can't fint no solution for that using SQL and can't find anything in google.
As you can see I have the parameter sortDirection and I have tried using it in multiple ways but always with errors... Tried Case Statements, IF statements and so on but it is complicated by the fact that I want to insert a keyword.
Help will be very much appriciated, I have tried must of the things that comes into mind but haven't been able to get it right.
You could use two order by fields:
CASE #sortDir WHEN 'ASC' THEN
CASE UPPER(#sortBy)
...
END
END ASC,
CASE #sortDir WHEN 'DESC' THEN
CASE UPPER(#sortBy)
...
END
END DESC
A CASE will evaluate as NULL if none of the WHEN clauses match, so that causes one of the two fields to evaluate to NULL for every row (not affecting the sort order) and the other has the appropriate direction.
One drawback, though, is that you'd need to duplicate your #sortBy CASE statement. You could achieve the same thing using dynamic SQL with sp_executesql and writing a 'ASC' or 'DESC' literal depending on the parameter.
That code is going to get very unmanageable very quickly as you'll need to double nest your CASE WHEN's... one set for the Column to order by, and nested set for whethers it's ASC or DESC
Might be better to consider using Dynamic SQL here...
DECLARE #sql nvarchar(max)
SET #sql = '
Select
tbl_houses.*
from tbl_houses
where
postal in (select zipcode from crm_zipcodes where web_region_id = ' + #webRegionID + ') ORDER BY '
SET #sql = #sql + ' ' + #sortBy + ' ' + #sortDirection
EXEC (#sql)
You could do it with some dynamic SQL and calling it with an EXEC. Beware SQL injection though if the user has any control over the parameters.
CREATE PROCEDURE GetAllHouses
set #webRegionID = 2
set #sortBy = 'case_no'
set #sortDirection = 'ASC'
AS
BEGIN
DECLARE #dynamicSQL NVARCHAR(MAX)
SET #dynamicSQL =
'
SELECT
tbl_houses.*
FROM
tbl_houses
WHERE
postal
IN
(
SELECT
zipcode
FROM
crm_zipcodes
WHERE
web_region_id = ' + CONVERT(nvarchar(10), #webRegionID) + '
)
ORDER BY
' + #sortBy + ' ' + #sortDirection
EXEC(#dynamicSQL)
END
GO