select a column where the column name is retrieved from a query - sql

I'm looking for a elegant way to select a column from table A where as the column name is retrieved from a query on table B.
A query on table B results in 'col01'
The Table A has several columns named 'col01','col02','col03',...
Final query should be for result
result from B | effective SQL query
'col01' | SELECT col01 FROM A
'col02' | SELECT col02 FROM A
I'm looking for pure SQL solution with no scripting. It should run with Oracle and/or MySQL.

I'm looking for pure SQL solution with no scripting.
This is not possible. You have to create the statements dynamically.

In a very simple case you can just about do it with a CASE statement, but this is unlikely to be of much use in the real world:
with a as (
select 'col_01_val_01' as col_01, 'col_02_val_01' as col_02,
'col_03_val_01' as col_03 from dual
union select 'col_01_val_02' as col_01, 'col_02_val_02' as col_02,
'col_03_val_02' as col_03 from dual
union select 'col_01_val_03' as col_01, 'col_02_val_03' as col_02,
'col_03_val_03' as col_03 from dual),
b as (
select 1 parm, 'col_01' value from dual
union select 2 parm, 'col_02' value from dual
union select 3 parm, 'col_03' value from dual)
select b.value as result_from_b,
case b.value
when 'col_01' then col_01
when 'col_02' then col_02
when 'col_03' then col_03 end as result_from_a
from a, b
where b.parm = 1;
RESULT_FROM_B RESULT_FROM_A
------------- -------------
col_01 col_01_val_01
col_01 col_01_val_02
col_01 col_01_val_03
The columns have to be the same type (or at least expressible as such in the case), and b can only return one row... And it isn't very pretty of course. For anything more complicated you need dynamic SQL as #a_horse_with_no_name has already suggested.

This could be done within a stored routine in MySQL. I don't know about Oracle as I haven't used it. You can find out more about MySQL stored procedures here and here (the 2nd link is a pretty good PDF which walks you through some simple examples).

Related

selecting only NON NULL values in Oracle sql table

I have a table that has 40 columns/headers and 15 rows(may vary due to the high volume records); In the records/data, many columns which have NULL values or in other words, these columns were not in a production environment, so no validation required or to list in the output.
I wanna list only the NON NULL values(Column vise) in the select table even if the entire Column is NULL.
COLUMNS
Col_A
Col_B
Col_C
Col_D
Col_E
Col_F
ROW1
Val_1
Val_2
NULL
Val_4
Val_5
Val_6
ROW2
Val_1
Val_2
NULL
Val_4
Val_5
NULL
Here I want to list all the columns except "Column C" which is NULL
In sql this is not possible, because that is not how a sql query works. In short this is what happens
You tell the database engine what columns you want to get back and what the conditions are (conditions filter rows, not columns). At this point the database does not know anything about the results. This is done using the query syntax.
The db engine runs the query and returns the result, row by row. The db engine does not know what is in those rows/columns.
The requirement is to skip columns that have no data. As explained above, that is not know at the time of running the query, but you could work around this, for example by creating a view that only has the columns with data. Bear in mind that this means that every query has to run at least once before the query itself, which could be a downside if you're talking about large datasets.
Lets create a sample table
CREATE TABLE tab1 (c1, c2, c3, c4) AS
(
SELECT 1,CAST(NULL AS NUMBER), 2,4 FROM DUAL UNION ALL
SELECT NULL,NULL, 1,3 FROM DUAL UNION ALL
SELECT 1,NULL, NULL,3 FROM DUAL UNION ALL
SELECT 1,NULL, 2,NULL FROM DUAL UNION ALL
SELECT 4,NULL, 3,4 FROM DUAL
);
Now it's not possible to know which columns have only NULL values before we run the query, but we can run a query to know which columns have only NULL values using an aggregate function like MAX, MIN OR SUM. Lets call this QUERY1. For example:
SELECT MAX(c1),MAX(c2),MAX(c3),MAX(c4) FROM tab1;
MAX(C1) MAX(C2) MAX(C3) MAX(C4)
---------- ---------- ---------- ----------
4 3 4
Now we can convert that select so it generates another select that that only selects the columns with not null values. Lets call this QUERY2.
SELECT
'SELECT '||
RTRIM(
NVL2(SUM(c1),'c1,','') ||
NVL2(SUM(c2),'c2,','') ||
NVL2(SUM(c3),'c3,','') ||
NVL2(SUM(c4),'c4,','')
,',')||' FROM tab1;' FROM tab1;
STMT
---------------------------------------------------------------
CREATE OR REPLACE VIEW tab1_v AS SELECT c1,c3,c4 FROM tab1;
There you go - this statement will only return the columns that have no NULL values. Note that this is not foolproof. If a row is created or updated after you run QUERY1 but before you run QUERY2 that would alter the results of QUERY1, it could not select the correct columns.

Column Mismatch in UNION queries

I have columns A,B in Table 1 and columns B,C in Table 2.Need to perform Union between them .
For example : select A,B from Table 1 UNION select 0,B from Table 2.
I dont need this zero to solve the column mismatch.Instead is there any other solution?
Am asking the question by providing simple example . But in my case the table structure is very large and the queries are already built.Now I need to fix this union query by replacing this zero.(due to DB2 upgrade)
Can anyone help?
For two legs A and B in a union to be union compatible it is required that:
a) A and B have the same number of columns
b) The types for each column in A is compatible with the corresponding column in B
In your query you can use null that is part of every type:
select a, b from T1
UNION
select null, b from T2
Under certain circumstances, you may have to explicitly cast null to the same type as A has (probably not in this case):
select a, b from Table 1
UNION
select cast(null as ...), b from Table 2
A column returned in a SQL result set can only have one data type.
A union or union all results in rows from the first query and the rows of the second query (in case of union they are deduplicated).
So the first column of the first query needs to match the data type of the first column of the second query.
You can check this by running a describe:
describe select a,b from t1
If you work within a GUI (JDBC Connection) you could also use
call admin_cmd('describe select a,b from t1')
So if the some column does not match you have to explicitly cast the data types.

Oracle SQL - Selecting column without knowing column name

Is it possible to select the value of the second column using something like an index or column position if i dont know the name of the column?
Select col(2) FROM (
Select 'a', 'b',' c', 'd' from dual
)
Is it possible? Sure. You could write a PL/SQL block that used dbms_sql to open a cursor using the actual query against dual, describe the results, bind a variable to whatever you find the second column to be, fetch from the cursor, and then loop. That would be a terribly involved and generally rather painful process but it could be done.
The SQL language does not define a way to do this in a static SQL statement and Oracle does not provide an extension that would allow this. I'd be rather concerned about the underlying problem that you're trying to solve, though, if you somehow know that you want the second column but don't know what that column represents. That's not something that makes a lot of sense in a relational database.
SELECT ORDINAL_POSITION, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'dual'
not sure if this is what you need.
If you don't know the name, just give it a nice name ;).
Select b FROM (
Select 'a', 'b' as b, 'c', 'd' from dual
)
It is possible in case when you know number of columns in the subquery:
SELECT COL2 FROM (
SELECT NULL COL1, NULL COL2, NULL COL3, NULL COL4
UNION ALL
select 'a', 'b', 'c', 'd' from dual
)
WHERE COL2 IS NOT NULL;
There are limitations:
query is hard to read and understand
you should know number of columns
value should not be NULL
not recommended for production use

While inserting multiple rows what does the statement 'select 1 from dual' do?

While inserting multiple rows into a table using the following style :
insert all
into ghazal_current (GhazalName,Rating) values('Ajab Apna Haal Hota Jo Visaal-e-Yaar Hota',5)
into ghazal_current (GhazalName,Rating) values('Apne Hothon Par Sajana Chahta Hun',4)
into ghazal_current (GhazalName,Rating) values('Shaam Se Aankh Mein Nami Si Hai',4)
into ghazal_current (GhazalName,Rating) values('Tumhe Yaad Ho Ke Na Yaad Ho',3)
select 1 from dual;
What does the statement select 1 from dual mean ? What is it here for ?
DUAL is a built-in table, useful because it is guaranteed to return only one row. This means DUAL may be used to get pseudo-columns such as user or sysdate, the results of calculations and the like. The owner of DUAL is SYS but it can be accessed by every user. DUAL is well-covered in the documentation. Find out more.
In your case, SELECT 1 FROM DUAL; will simply returns 1. You need it because the INSERT ALL syntax demands a SELECT clause but you are not querying the input values from a table.
Brief re-introduction to one-row tables
Some SQL databases require all values to come FROM a table or table-like object, whereas others permit queries to construct values ex nihilo:
-- MySQL, sqlite, PostgreSQL, HSQLdb, and many others permit
-- a "naked" select:
SELECT 1;
-- Others *require* a FROM target, like Oracle.
SELECT 1 FROM DUAL;
-- ...and Firebird/Interbase:
SELECT 1 FROM RDB$DATABASE;
-- ...and DB2:
SELECT 1 FROM SYSIBM.SYSDUMMY1;
Here the cardinality of DUAL is important. If it had more than one row, your result set would have more than one row. What happens, for example, when you SELECT 1 FROM A_Table_With_Ten_Rows?
Why DUAL is used here
The SQL construct VALUES (<row-value-expression>) is a row value constructor. VALUES (1, 2, 3) "creates" a row of values just as SELECT 1, 2, 3 does.
Oracle, of course, requires that these values come FROM somewhere.
As a demonstration, instead of SELECTing from DUAL at the end of the INSERT ALL, try a table with N rows, and you'll see that each VALUES() row is inserted N times.
There are some samples about using dual in Queries:
select sysdate from dual /--it returns date of system
SELECT chr(223) FROM dual /--it returns character of AsciÙ‡i code
select my_sequence.nextval from dual; /-- It returns the next value of a sequence
select to_char(sysdate,'yyyy/mm/dd','nls_calendar=persian')from dual
/--returns persian date of system

return a default row in sql

Is it possible in oracle sql to return a default row if no rows found.
I have a process where in rows fetched will be put in a flat ascii file.
now i have a requirement that if there are no rows fetched by the sql query then there should be a default row in the ascii file.
is it possible in sql to output a default row if no rows fetched by the query
note: i dont want to use pl/sql.
For complex queries where the overhead on finding out if there is a row in the result set is onerous or the query is just very large and unwieldy, then a subquery factoring clause might be beneficial:
With my_query as
(
select a, b, c from foobar where foo='FOO'
)
Select a,b,c
From my_query
Union All
Select ...
From dual
Where Not Exists
(Select 1 from my_query)
/
You could use UNION ALL for this:
select a, b, c from foobar
where foo='FOO'
union all
select 'def', 'ault', 'value' from dual
where not exists ( select 'x' from foobar where foo='FOO' )
I suspect that it would be cleaner to have the process that the writes the ASCII file write the default data if no rows are returned rather than getting Oracle to do it. If the query that you're using is expensive, you'd significantly increase that cost if you fudge it to return a default row as ammoQ and David Oniell have done.
There is another (sad, twisted) option. No CTEs or subquery repetition needed.
select
coalesce(a, 'def'),
coalesce(b, 'ault'),
coalesce(c, 'value')
from foobar
right join (select 1 from dual) on 1=1
where foobar.some_condition;