Dynamic Columns in - sql

I have table with the following static columns
ID Sys_Date Name prop_name1 prop_name2 prop_name3 prop_value1 prop_value2 prop_value3
10 11/2/2011Java class method parameter Imanager getOrders orderNumber
I need to write SQL query which get an input property name like “method” and go over (prop_name1 prop_name2 prop_name3 ) and check which column
Is equal to “method” in case I found it I need to jump 3 columns to the proper value which is “getOrders” and get the value from there where
prop_name1 is mapping to prop_value1
prop_name2 is mapping to prop_value2
prop_name3 is mapping to prop_value3
how can I do it with sql query?
Thanks in advance

You could do something like this:
select name,value
from
(
select id, prop_name name, prop_name value
from table
union
select id, prop_name2 name, prop_name2 value
from table
union
select id, prop_name3 name, prop_name3 value
from table
)
where name = 'method'
...which is basically shoe-horning your data into a more easily queryable structure. You'd be better off changing the table structure, though..

Related

What is the best method to summarise my data and add a new attribute?

I want to declare that VARIABLE is euqal to the last part of a string in my 'campaign' column.
My campaign column looks like this:
live_c_account_p_search_ct_dsa_l_location
I want to be able to extract the text following l and create a new column which I can later group by.
Either of the below approaches should be fine.
with data as (
select 'a_b_c_d' as campaign union all
select 'x_y_z' union all
select 'live_c_account_p_search_ct_dsa_l_location'
)
select
campaign,
regexp_extract(campaign, '.*_(.*)') as method1,
array_reverse(split(campaign,'_'))[safe_ordinal(1)] as method2
from data

How to execute a select with a WHERE using a not-always-existing column

Simple example: I have some (nearly) identical tables with personal data (age, name, weight, ...)
Now I have a simple, but long SELECT to find missing data:
Select ID
from personal_data_a
where
born is null
or age < 1
or weight > 500
or (name is 'John' and surname is 'Doe')
Now the problem is:
I have some personal_data tables where the column "surname" does not exit, but I want to use the same SQL-statement for all of them. So I have to check (inside the WHERE clause) that the last OR-condition is only used "IF the column surname exists".
Can it be done in a simple way?
You should have all people in the same table.
If you can't do that for some reason, consider creating a view. Something like this:
CREATE OR REPLACE VIEW v_personal_data
AS
SELECT id,
born,
name,
surname,
age,
weight
FROM personal_data_a
UNION ALL
SELECT id,
born,
name,
NULL AS surname, --> this table doesn't contain surname
age,
weight
FROM personal_data_b;
and then
SELECT id
FROM v_personal_data
WHERE born IS NULL
OR age < 1
OR ( name = 'John'
AND ( surname = 'Doe'
OR surname IS NULL))
Can it be done in a simple way?
No, SQL statements work with static columns and the statements will raise an exception if you try to refer to a column that does not exist.
You will either:
need to have a different query for tables with the surname column and those without;
have to check in the data dictionary whether the table has the column or not and then use dynamic SQL to build your query; or
to build a VIEW of the tables which do not have that column and add the column to the view (or add a GENERATED surname column with a NULL value to the tables that are missing it) and use that instead.
While dynamic predicates are usually best handled by the application or by custom PL/SQL objects that use dynamic SQL, you can solve this problem with a single SQL statement using DBMS_XMLGEN, XMLTABLE, and the data dictionary. The following code is not what I would call "simple", but it is simple in the sense that it does not require any schema changes.
--Get the ID column from a PERSONAL table.
--
--#4: Get the IDs from the XMLType.
select id
from
(
--#3: Convert the XML to an XMLType.
select xmltype(personal_xml) personal_xmltype
from
(
--#2: Convert the SQL to XML.
select dbms_xmlgen.getxml(v_sql) personal_xml
from
(
--#1: Use data dictionary to create SQL statement that may or may not include
-- the surname predicate.
select max(replace(replace(
q'[
Select ID
from #TABLE_NAME#
where
born is null
or age < 1
or weight > 500
or (name = 'John' #OPTIONAL_SURNAME_PREDICATE#)
]'
, '#TABLE_NAME#', table_name)
, '#OPTIONAL_SURNAME_PREDICATE#', case when column_name = 'SURNAME' then
'and surname = ''Doe''' else null end)) v_sql
from all_tab_columns
--Change this literal to the desired table.
where table_name = 'PERSONAL_DATA_A'
)
)
where personal_xml is not null
)
cross join xmltable
(
'/ROWSET/ROW'
passing personal_xmltype
columns
id number path 'ID'
);
See this db<>fiddle for a runnable example.

Will a PIVOT meet my requirements?

Please see the DDL below:
CREATE TABLE Person (PersonNo int, Name varchar, Age int,address varchar(100))
Is it possible to SELECT the data in the following format using a single query:
PersonNo Name
PersonNo Age
PersonNo Address
I would need a column to identify the type of row e.g. Name. The more I think about this the more I don't think I can do it. I am currently trying to do it with a pivot.
One option would be to use UNION ALL (just remember to convert the int to varchar):
select personno, name as value, 'Name' as type
from person
union all
select personno, CONVERT(varchar(10), age), 'Age' as type
from person
union all
select personno, address, 'Address' as type
from person
SQL Fiddle Demo
Also please note -- you should define a length for the Name field. As is, it can only contain a single character.
You are looking for an UNPIVOT, not a PIVOT
SELECT
PersonNo
,ColumnName
,ColumnValue
FROM Person t1
UNPIVOT(ColumnValue FOR ColumnName in ([Name],[Age],[Address])) t2

find unique rows using SQL?

I want to return all the rows from a table which are unique. I.e. if a certain field in two rows contain the same name, that name shouldn't be shown.
Since you want only the uniques names (and not an unique row for every names like you could have with DISTINCT), you have to use a GROUP BY and a HAVING (instead of a WHERE, because your parameter is the result of a function, not a variable) :
SELECT name FROM myTable GROUP BY name HAVING COUNT(name) = 1
SELECT DISTINCT column_name FROM table
If you want the complete rows, then use row_number() or distinct on:
select distinct on (name) t.*
from table t
order by name;

How can I write this SQL SELECT query for this table?

I have this situation in a certain table:
id | name
1 'Test'
2 'Test'
3 'Test'
How can I make a query to SELECT by distinct the name? I also need the ID column, even if I get the first occurrence of the element, e.g. "if the name column repeats, give me the first record with this repetition."
select name, MIN(ID)
from aCertainTable
group by name