dynamic sql to dynamically create column name from field value - sql

Here is my Schema :
Table t1:
x1 y1
1 2
Table t2:
x2 y2
1 'x1'
2 'y2'
I need to use dynamic SQL to join these two tables and the join column of table t1 should be decided by the value of column y2.
I tried a very ugly and not-working SQL of cause of no use.
select * from t1 join t2 t on t2.x2 = t1.(select y2 from t2 where x2=t.x2);
I am very new to dynamic SQL so not sure how to achieve this.
P.S. : The values above are just for example. Actually, both the tables are dynamically created hence not necessary the column names will be same. Also, the column numbers may differ hence pivoting might not be that useful

You don't need dynamic SQL, such more logic in the on clause:
select *
from t1 join
t2 t
on t2.x2 = t1.x1 and t2.y2 = 'x1' or
t2.x2 = t1.y1 and t2.y2 = 'y1';

In my experience this is best handled at the program level (creating these dynamic queries).
You don't know the table names but it doesn't mean you can't create a store for the dynamic names (ie. another table, called "tables_meta" that contains a listing of all the dynamic tables).
Likewise, if you wanted a dynamic table to have dynamic fields as well, you could create a table to store the mapping between the dynamic table created and the associated dynamic fields ("fields_meta" containing a one to many association between table and its dynamic fields).
Querying the "meta" tables for table name and then building your query programmaticly using that retrieved name (and likewise fields) can allow you run any queries you want against the dynamic objects.
As for joining dynamic tables specifically, doing so assumes you have some insight into the fields that result in a meaningful join. If this is the case, you could create your dynamic tables, but with at least one static field with meaningful data, that would allow you to query your "tables_meta" for a table, then build a query in your program with that result to join your table X on its static field "join_here" with (repeat read from tables meta to get Y) and join it on Y."join_here" (the static field)
Very rough example sudo code:
List<String> sql-getDynamicTables = "select table_name from tables_meta";<br />
(results in X, Y, Z...)
if(sql-getDynamicTables.size > 1) { (make sure we have stuff to join on)
(Start building the query for the join)
String sql-performJoin = "select * from" + sql-getDynamicTables.get(0);
for( each additional database found ) {
sql-performJoin += " join " + sql-getDynamicTables.get(index-i) + " on " + sql-getDynamicTables.get(index-i)+".staticField = "(or replace that with a separate variable containing the dynamic field)+ sql-getDynamicTables.get(0)".staticField, ";
}
(remove any trailing commas)
(add any where clause or whatever modifications to the query)
(run the query sql-performJoin)
}
Again, column names might not be the same but you can query for them like we do the dynamic table names and build the query with that instead of ".staticField" or whatever you choose.
Just make sure you know that the data your joining on provides a meaningful join.
Just as a note: Dynamic SQL is quite painful and introduces a lot of considerations (duplicating table names, etc). It might be worth investigating alternatives if your still up in the air about it.

Related

Optimize view that dynamically choose a table or another

So the problem is that I have three huge table with same structure, and I need to show the results of one of them depending on result from another query.
So my order table looks like that:
code order
A 0
B 2
C 1
And I need to retrieve data from t_results
My approach (which is working) looks like this:
select *
from t_results_a
where 'A' in (
select code
from t_order
where order = 0
)
UNION ALL
select *
from t_results_b
where 'B' in (
select code
from t_order
where order = 0
)
UNION ALL
select *
from t_results_c
where 'C' in (
select code
from t_order
where order = 0
)
Is there anyway to not scan all three tables, as I am working with Athena so I can't program?
I presume that changing your database schema is not an option.
If it were, you could use one database table and add a CODE column whose value would be either A, B or C.
Basically the result of the SQL query on your ORDER table determines which other database table you need to query. For example, if CODE in table ORDER is A, then you have to query table T_RESULTS_A.
You wrote in your question
I am working with Athena so I can't program
I see that there is both an ODBC driver and a JDBC driver for Athena, so you can program with either .NET or Java. So you could write code that queries the ORDER table and use the result of that query to build another query string to query just the relevant table.
Another thought I had was dynamic SQL. Oracle database supports it. I can create a string containing variables where one variable is the database table name and have Oracle interpret the string as SQL and execute it. I briefly searched the Internet to see whether Athena supports this (as I have no experience with Athena) but found nothing - which doesn't mean to say that it does not exist.

Using table variables in Oracle Stored Procedure

I have lots of experience with T-SQL (MS SQL Server).
There it is quite common to first select some set of records into a
table variable or say temp table t, and then work with this t
throughout the whole SP body using it just like a regular table
(for JOINS, sub-queries, etc.).
Now I am trying the same thing in Oracle but it's a pain.
I get errors all the way and it keeps saying
that it does not recognize my table (i.e. my table variable).
Error(28,7): PL/SQL: SQL Statement ignored
Error(30,28): PL/SQL: ORA-00942: table or view does not exist
I start thinking what at all is possible to do with this
table variable and what not (in the SP body) ?
I have this declaration:
TYPE V_CAMPAIGN_TYPE IS TABLE OF V_CAMPAIGN%ROWTYPE;
tc V_CAMPAIGN_TYPE;
What on Earth can I do with this tc now in my SP?!
This is what I am trying to do in the body of the SP.
UPDATE ( SELECT t1.STATUS_ID, t2.CAMPAIGN_ID
FROM V_CAMPAIGN t1
INNER JOIN tc t2 ON t1.CAMPAIGN_ID = t2.CAMPAIGN_ID
) z
SET z.STATUS_ID = 4;
V_CAMPAIGN is a DB view, tc is my table variable
Presumably you are trying to update a subset of the V_CAMPAIGN records.
While in SQLServer it may be useful to define a 'temporary' table containing the subset and then operate on that it isn't necessary in Oracle.
Simply update the table with the where clause you would have used to define the temp table.
E.g.
UPDATE v_campaign z
SET z.status_id = 4
WHERE z.column_name = 'a value'
AND z.status <> 4
I assume that the technique you are familiar with is to minimise the effect of read locks that are taken while selecting the data.
Oracle uses a different locking strategy so the technique is mostly unnecessary.
Echoing a comment above - tell us what you want to achieve in Oracle and you will get suggestions for the best way forward.

understanding existing SQL query

I am trying to read some exiting SQL queries written for MS SQL server.
I don't have access to database, table names etc.. Just raw query format...And I need to do some analysis on the fields required..
I need some help in understanding what certain query statements are doing...such as in the following block...
select FIELD1, x2.FIELD2
into #temp
from #temp1 x1 join #temp2 x2
on x1.FIELD1 = x2.FIELD2
and x1.FIELD3 = x2.MAXOCCUR
I have basic SQL understanding.. But I need to understand couple of things....Why does 'into' and 'from' statements have a '#' infront of table names.....what are x1 and x2 in this case. Why not just say
temp1.FIELD1 = temp2.FIELD2 instead of
x1.FIELD1 = x2.FIELD2
.....Am I missing something or is this query formed weird to begin with....I understand joins etc...
Can someone help me out...
Thanks
That is selecting from two already temp existing temp tables into a new temp table. The x1.FIELD1 is called aliasing. It's used so you don't have to type full table names when writing the query
As mentioned, the # signs indicate a TEMPORARY table.
x1 and x2 are used as "table alias" in this query. Yes, you could write
temp1.FIELD1 = temp2.FIELD2 instead of x1.FIELD1 = x2.FIELD2
but, consider if the tables had long names. Then using an alias makes the query easier to read (for humans. the computer doesn't really care).

Jet engine (Access) : Passing a list of values to a stored procedure

I am currently writing a VBA-based Excel add-in that's heavily based on a Jet database backend (I use the Office 2003 suite -- the problem would be the same with a more recent version of Office anyway).
During the initialization of my app, I create stored procedures that are defined in a text file. Those procedures are called by my app when needed.
Let me take a simple example to describe my issue: suppose that my app allows end-users to select the identifiers of orders for which they'd like details. Here's the table definition:
Table tblOrders: OrderID LONG, OrderDate DATE, (other fields)
The end-user may select one or more OrderIDs, displayed in a form - s/he just has to tick the checkbox of the relevant OrderIDs for which s/he'd like details (OrderDate, etc).
Because I don't know in advance how many OrderID s/he will select, I could dynamically create the SQL query in the VBA code by cascading WHERE clauses based on the choices made on the form:
SELECT * FROM tblOrders WHERE OrderID = 1 OR OrderID = 2 OR OrderID = 3
or, much simpler, by using the IN keyword:
SELECT * FROM tblOrders WHERE OrderID IN (1,2,3)
Now if I turn this simple query into a stored procedure so that I can dynamically pass list of OrderIDs I want to be displayed, how should I do? I already tried things like:
CREATE PROCEDURE spTest (#OrderList varchar) AS
SELECT * FROM tblOrders WHERE OrderID IN (#OrderList)
But this does not work (I was expecting that), because #OrderList is interpreted as a string (e.g. "1,2,3") and not as a list of long values. (I adapted from code found here: Passing a list/array to SQL Server stored procedure)
I'd like to avoid dealing with this issue via pure VBA code (i.e. dynamically assigning list of values to a query that is hardcoded in my application) as much as possible. I'd understand if ever this is not possible.
Any clue?
You can create the query-statement string dynamically. In SQL Server you can have a function whose return value is a TABLE, and invoke that function inline as if it were a table. Or in JET you could also create a kludge -- a temporary table (or persistent table that serves the function of a temporary table) that contains the values in your in-list, one per row, and join on that table. The query would thus be a two-step process: 1) populate temp table with INLIST values, then 2) execute the query joining on the temp table.
MYTEMPTABLE
autoincrementing id
QueryID [some value to identify the current query, perhaps a GUID]
myvalue one of the values in your in-list, string
select * from foo
inner join MYTEMPTABLE on foo.column = MYTEMPTABLE.myvalue and MYTEMPTABLE.QueryId = ?
[cannot recall if JET allows ANDs in INNER JOIN as SQL Server does --
if not, adjust syntax accordingly]
instead of
select * from foo where foo.column IN (... )
In this way you could have the same table handle multiple queries concurrently, because each query would have a unique identifier. You could delete the in-list rows after you're finished with them:
DELETE FROM MYTEMPTABLE where QueryID = ?
P.S. There would be several ways of handling data type issues for the join. You could cast the string value in MYTEMPTABLE as required, or you could have multiple columns in MYTEMPTABLE of varying datatypes, inserting into and joining on the correct column:
MYTEMPTABLE
id
queryid
mytextvalue
myintvalue
mymoneyvalue
etc

update one table using data from another table

I am trying to update my current table by drawing data from another table.
My database (dbo_finance)
column - test
The other database is assestsc and I am going to pull the data from column issuename1,
however I only want to pull the issuename1 when the field [MinSecClass] is = 9.
This is what I wrote
UPDATE dbo_finance
SET [dbo_finance].cusip9 = AssetsC.cusip
FROM dbo_finance INNER JOIN AssetsC ON dbo_finance.test = AssetsC.[IssueName1]
WHERE (AssetsC.MinSecClass = 9)
Thanks, first time really using SQL
Well I would use aliases, it's a good habit to get into:
UPDATE f
SET [dbo_finance].cusip9 = AssetsC.cusip
FROM dbo_finance f
INNER JOIN AssetsC a ON f.test = a.[IssueName1]
WHERE (a.MinSecClass = 9)
Now that will work fine if the assets table will only return one value for cuspid for each record. If this is a one to many relationship you may need to get more complex to truly get the answer you want.
I see several serious design flaws in your table structure. First joins fields that are dependant as something as inherently unstable as issue name are a very poor choice. You want PK and FK field to be unchanging. Use surrogate keys instead and a unique index.
The fact that you have a field called cusp9 indicates to me that you are denormalizing the data. Do you really need to do this? Do you undestand that this update will have to run in a trigger ever time the cuspid assoicated with MinSecClass changes? Whya re you denormalizing? Do you currently have performance problems? A denormalized table like this can be much more difficult to query when you need data from several of these numbered fields. Since you already have the data in the assets table what are you gaining except a maintenance nightmare by duplicating it?
UPDATE dbo_finance
SET cusip9 = (
SELECT A1.cusip
FROM AssetsC AS A1
WHERE dbo_finance.test = A1.IssueName1
AND AssetsC.MinSecClass = 9
)
WHERE EXISTS (
SELECT *
FROM AssetsC AS A1
WHERE dbo_finance.test = A1.IssueName1
AND A1.MinSecClass = 9
);
Because you're using SQL 2008, you can take advantage of the new(ish) MERGE statement.
MERGE INTO dbo_finance
USING (SELECT IssueName1, cusip FROM AssetsC WHERE MinSecClass = 9) AS source
ON dbo_finance.test = source.IssueName1
WHEN MATCHED THEN UPDATE SET dbo_finance.cusip9 = source.cusip;