Specifying a DB table dynamically? Is it possible? - select

I am writing a BSP and based on user-input I need to select data from different DB tables. These tables are in different packages. Is it possible to specify the table I want to use, based on its path, like this:
data: path1 type string value 'package1/DbTableName',
path2 type string value 'package2/OtherDbTableName',
table_to_use type string.
if some condition
table_to_use = path1.
elseif some condition
table_to_use = path2.
endif.
select *
from table_to_use
...
endselect
I am new to ABAP & Open SQL and am aware this could be an easy/silly question :) Any help at all would be very much appreciated!

You can define the name of the table to use in a variable, and then use the variable in the FROM close of your request :
data tableName type tabname.
if <some condition>.
tableName='PA0001'.
else.
tableName='PA0002'.
endif.
select * from (tableName) where ...
there are a few limitation to this method, as the stable can not contains fields of type RAWSTRING, STRING or SSTRING.
as for the fact that the table are in different package, i don't think it matters.
Regards,

Related

Orange3 : String Variable

I do not manage to create an Orange table with StringVariables.
The following code:
d = Orange.data.Domain([Orange.data.StringVariable("s")])
makes this error:
TypeError: variables must be primitive
It seems that StringVariable is for metadata only. So I'm worried about this because my data has a lot of strings that it would be crazy to put in a discrete structure (each string value is different).
Is there a solution for putting strings in a table ?
Thanks in advance for the answers,
Best,
mike
This question might be old but I found it via Google and wanted to provide a simple example of how to use meta "columns".
You need to specify the meta variables the same way you specify the "normal" variables just do it inside the metas parameter inside the Domain constructor.
from Orange.data import *
taskid = StringVariable(name="taskid")
logdata = StringVariable(name="logdata")
domain = Domain([] , metas=[taskid, logdata])
data = Table(domain, [
["uuid1","some more stuff"],
["uuid2","some more stuff"]
]);
out_data = data;

How do I get the contents of all of the nodes in a root node with SQL and XQuery?

I have the following table structure:
CREATE TABLE SpecialTable
(
Key UNIQUEIDENTIFIER,
XMLField VARCHAR(MAX)
)
In the first tuple:
Key = "28384841-17283848-7836-18292939"
XMLField =
"<RootNode>
<ForeignKey>92383829-27374848-1298-19283789</ForeignKey>
<ForeignKey>47585853-27374848-4759-19283939</ForeignKey>
<ForeignKey>37383829-27374848-3747-19283930</ForeignKey>
</RootNode>"
In another tuple, I see:
Key = "89984841-17283848-7836-18292939"
XMLField =
"<RootNode>
<ForeignKey>92383829-27374848-1298-19283789</ForeignKey>
<ForeignKey>37383829-27374848-3747-19283930</ForeignKey>
</RootNode>"
In a further tuple, I see:
Key = "11114841-17283848-7836-18292939"
XMLField =
"<RootNode>
<ForeignKey>37383829-27374848-3747-19283930</ForeignKey>
</RootNode>"
What I need to do is to get the following dataset out:
Key ForeignKey
28384841-17283848-7836-18292939 92383829-27374848-1298-19283789
28384841-17283848-7836-18292939 47585853-27374848-4759-19283939
28384841-17283848-7836-18292939 37383829-27374848-3747-19283930
89984841-17283848-7836-18292939 92383829-27374848-1298-19283789
89984841-17283848-7836-18292939 37383829-27374848-3747-19283930
11114841-17283848-7836-18292939 37383829-27374848-3747-19283930
I must say that this is a simplified data set and that the data was more complex than this and I have got to a point where I cannot get any further.
I have tried this:
SELECT sp.Key,
x.XmlCol.Query('.')
FROM SpecialTable AS sp
CROSS APPLY sp.XMLField.nodes('/RootNode') x(XmlCol)
However, it seems just to show the Key and the whole of the XML of the XMLField.
Also, I tried this:
SELECT sp.Key,
x.XmlCol.Query('ForeignKey[text]')
FROM SpecialTable AS sp
CROSS APPLY sp.XMLField.nodes('/RootNode') x(XmlCol)
And I get only the first value in the first ForeignKey node and not the others.
What am I doing wrong?
Kindest regards,
QuietLeni
First of all - if your data looks like XML, quacks like XML, smells like XML - then it IS XML and you should use the XML datatype to store it!
Also: be aware that Key is a very generic term, and also a T-SQL reserved keyword, so it makes for a really bad column name - use something more meaningful that doesn't clash with a keyword!
Once you've done that, you should be able to use this code to get your desired results:
SELECT
[Key],
ForeignKey = xc.value('.', 'varchar(50)')
FROM
dbo.SpecialTable
CROSS APPLY
XMLField.nodes('/RootNode/ForeignKey') AS XT(XC)
This will only work if you column XMLField is of XML datatype !! (which it really should be anyway)

Assigning a whole DataStructure its nullind array

Some context before the question.
Imagine file FileA having around 50 fields of different types. Instead of all programs using the file, I tried having a service program, so the file could only be accessed by that service program. The programs calling the service would then receive a DataStructure based on the file structure, as an ExtName. I use SQL to recover the information, so, basically, the procedure would go like this :
Datastructure shared by service program :
D FileADS E DS ExtName(FileA) Qualified
Procedure called by programs :
P getFileADS B Export
D PI N
D PI_IDKey 9B 0 Const
D PO_DS LikeDS(FileADS)
D LocalDS E DS ExtName(FileA) Qualified
D NullInd S 5i 0 Array(50) <-- Since 50 fields in fileA
//Code
Clear LocalDS;
Clear PO_DS;
exec sql
SELECT *
INTO :LocalDS :nullind
FROM FileA
WHERE FileA.ID = :PI_IDKey;
If SqlCod <> 0;
Return *Off;
EndIf;
PO_DS = LocalDS;
Return *On;
P getFileADS E
So, that procedure will return a datastructure filled with a record from FileA if it finds it.
Now my question : Is there any way I can assign the %nullind(field) = *On without specifying EACH 50 fields of my file?
Something like a loop
i = 1;
DoW (i <= 50);
if nullind(i) = -1;
%nullind(datastructure.field) = *On;
endif;
i++;
EndDo;
Cause let's face it, it'd be a pain to look each fields of each file every time.
I know a simple chain(n) could do the trick
chain(n) PI_IDKey FileA FileADS;
but I really was looking to do it with SQL.
Thank you for your advices!
OS Version : 7.1
First, you'll be better off in the long run by eliminating SELECT * and supplying a SELECT list of the 50 field names.
Next, consider these two web pages -- Meaningful Names for Null Indicators and Embedded SQL and null indicators. The first shows an example of assigning names to each null indicator to match the associated field names. It's just a matter of declaring a based DS with names, based on the address of your null indicator array. The second points out how a null indicator array can be larger than needed, so future database changes won't affect results. (Bear in mind that the page shows a null array of 1000 elements, and the memory is actually relatively tiny even at that size. You can declare it smaller if you think it's necessary for some reason.)
You're creating a proc that you'll only write once. It's not worth saving the effort of listing the 50 fields. Maybe if you had many programs using this proc and you had to create the list each time it'd be a slight help to use SELECT *, but even then it's not a great idea.
A matching template DS for the 50 data fields can be defined in the /COPY member that will hold the proc prototype. The template DS will be available in any program that brings the proc prototype in. Any program that needs to call the proc can simply specify LIKEDS referencing the template to define its version in memory. The template DS should probably include the QUALIFIED keyword, and programs would then use their own DS names as the qualifying prefix. The null indicator array can be handled similarly.
However, it's not completely clear what your actual question is. You show an example loop and ask if it'll work, but you don't say if you had a problem with it. It's an array, so a loop can be used much like you show. But it depends on what you're actually trying to accomplish with it.
for old school rpg just include the nulls in the data structure populated with the select statement.
select col1, ifnull(col1), col2, ifnull(col2), etc. into :dsfilewithnull where f.id = :id;
for old school rpg that can't handle nulls remove them with the select statement.
select coalesce(col1,0), coalesce(col2,' '), coalesce(col3, :lowdate) into :dsfile where f.id = :id;
The second method would be easier to use in a legacy environment.
pass the key by value to the procedure so you can use it like a built in function.
One answer to your question would be to make the array part of a data structure, and assign *all'0' to the data structure.
dcl-ds nullIndDs;
nullInd Ind Dim(50);
end-ds;
nullIndDs = *all'0';
The answer by jmarkmurphy is an example of assigning all zeros to an array of indicators. For the example that you show in your question, you can do it this way:
D NullInd S 5i 0 dim(50)
/free
NullInd(*) = 1 ;
Nullind(*) = 0 ;
*inlr = *on ;
return ;
/end-free
That's a complete program that you can compile and test. Run it in debug and stop at the first statement. Display NullInd to see the initial value of its elements. Step through the first statement and display it again to see how the elements changed. Step through the next statement to see how things changed again.
As for "how to do it in SQL", that part doesn't make sense. SQL sets the values automatically when you FETCH a row. Other than that, the array is used by the host language (RPG in this case) to communicate values back to SQL. When a SQL statement runs, it again automatically uses whatever values were set. So, it either is used automatically by SQL for input or output, or is set by your host language statements. There is nothing useful that you can do 'in SQL' with that array.

simple where clause SSRS 2005 parameter not working

this should be a simple thing but I've spent hours to no avail. Basically, I need to look up a salesrep # in a SQL database using the user's Window's user id. The format of the user id is
"Norstar\kjones" and I need the "kjones" portion of it.
using the split function, I am able to pull just the 'kjones' part out:
split(User!UserID,"\").GetValue(1)
I've created a parameter called SlsmnNum and created a dataset to be used to look up the salesrep # using the user id (the slsm_num field is a varchar, not an integer):
select slsm_num from Salesman_Msid where slsm_msid = ''' + split(User!UserID,"\").GetValue(1) + '''
However, I get no results. How can I get the select to work?
alternatively, I tried the following:
in parameter SlsmnNum, I set the default to an expression using:
split(User!UserID,"\").GetValue(1) and this returns 'kjones', as expected.
I created a SECOND parameter (which is positioned BELOW the SlsmnNum parameter), SlsmnNum2, that has a default (and an available) value using a query, which is a dataset containing the following select statement:
select slsm_num from Salesman_Msid where slsm_msid = (#SlsmnNum)
When I run the query on the Data tab, when I type in 'kjones' into the parameter box, it returns '1366', the salesrep # I'm expecting.
But, when I Preview the report, all I get in SlsmnNum2 box is Select a Value and nothing is there (it should return '1366').
Any help would be greatly appreciated!
Try your first approach with Query Text as
="select slsm_num from Salesman_Msid where slsm_msid = '" & split(User!UserID,"\").GetValue(1) & "'"

SQL Report Builder 3.0 Multi Value Parameter

I have a report that is required to accept number ranges and comma delimited values in a text field parameter. The parameter is for 'Account Type' and they want to be able to enter "1,2,5-9" and that will take integer values of 1,2,5,6,7,8,9. I know how to do this with a single value but never with a range.
The example code I would use for a single value is:
SELECT
arcu.vwARCUAccount.AccountType
,arcu.vwARCUAccount.ACCOUNTNUMBER
FROM
arcu.vwARCUAccount
WHERE
arcu.vwARCUAccount.AccountType = #AccountType
Any information would be extremely helpful. Someone on my team already estimated it and said it could be done without even realising that they wanted a range so now I am stuck figuring it out. I bet everyone here has been in my position so I thank everyone in advance.
There are several things you want to do.
A. Set up a parameter that is data type 'integer' and ensure you select the checkbox 'Allow multiple values'. Set it's value to be 'Ints'. Hit okay for now.
This essentially set up an array available list of a data set that you define for that type of data type that can be passed more than one dataset.
B. Create a simple dataset called 'values' that is like so
declare #Ints table ( id int);
insert into #Ints values (1),(2),(5),(6),(7),(8),(9)
C. Go back to your variable in step one and open up it's properties. Select 'Available Values' on the side pane. Choose radio button 'Get values from a query'. List your data set as 'values' and your value and label to be 'id'.
You have now bound your parameter array to values you specified. However a user DOES NOT have to just choose one or all of these but choose one or many of them.
D. You need to set up your main dataset(which I assume you already did before coming here). For the purpose of my example I will make a simple one up. I create a dataset called person:
declare #Table Table ( personID int identity, person varchar(8));
insert into #Table values ('Brett'),('Brett'),('Brett'),('John'),('John'),('Peter');
Select *
from #Table
where PersonID in (#Ints)
The important part is the predicate showing:
'where PersonID in (#Ints)'
This tells the dataset that it is dependent on the user to select a value in this array parameter.
I'm not completely proficient with tsql but what about using reg expressions?
See LIKE (Transact-SQL)
Such as:
arcu.vwARCUAccount.AccountType like '[' + replace(#AccountType, ',','') + ']'
This could work. As a broud brush try:
Remove the filter of the account type from the tsql.
Create a vb function that inputs a number, this being the account type, and tests to see if it is in the parameter string supplied by the user and outputs a 1 or 0. Vb Functions
Function test(byval myin as integer, byval mylimits as string) as integer
'results as 1 or 0
dim mysplit as string()= Split(mylimits, ",")
dim mysplit2 as string(1)
'look through all separated by a ","
For Each s As String In mysplit
'does there exists a range, i.e. "-"?
if s like "%-%" then
mysplit2 = split(s, "-")
'is the value between this range?
if myin >= mysplit(0) andalso myin <= mysplit(1) then
return 1
end if
'is the value equal to the number?
elseif s = myin then
return 1
end if
Next s
return 0
End
3. Create a filter on the dataset using the vb function with the account type as the input equal to 1.
=code.test(Fields!AccountType.Value, Paramaters!MyPar.Value)