SQL - Create table from Select + user defined columns and values - sql

Currently I have the following SELECT statement:
CREATE TABLE TEST AS
SELECT ROW_ID,
PROM_INTEG_ID,
INTEGRATION_ID,
BILL_ACCNT_ID,
SERV_ACCT_ID,
CFG_STATE_CD
FROM PRODUCTS
WHERE PROD_ID = 'TestProduct'
AND STATUS_CD = 'Active';
However I have to add some additional columns which do not exist in the PRODUCTS table and define them with my own name .e.g HIERARCHY
I tried using the WITH operand in my SQL query but it keeps failing as the syntax is wrong.
CREATE TABLE TEST AS
SELECT ROW_ID,
PROM_INTEG_ID,
INTEGRATION_ID,
BILL_ACCNT_ID,
SERV_ACCT_ID,
CFG_STATE_CD
WITH
PRODUCT_HEIRARCHY varchar2(30) 'Test123Value'
FROM PRODUCT
WHERE PROD_ID = 'TestProduct'
AND STATUS_CD = 'Active';
So in summary, I want to pull in columns from an existing table as well as defining some of my own.
Any help appreciated

Just add the columns to the select:
CREATE TABLE TEST AS
SELECT ROW_ID, PROM_INTEG_ID, INTEGRATION_ID, BILL_ACCNT_ID, SERV_ACCT_ID, CFG_STATE_CD,
CAST('Test123Value' AS VARCHAR2(30)) as PRODUCT_HIERARCHY
FROM PRODUCTS
WHERE PROD_ID = 'TestProduct' AND STATUS_CD = 'Active';
Note that the cast() is not necessary. But it is a good idea if you want the column to have a specific type.

Also using CTE i.e. WITH clause as known commonly, you could create table.
CREATE TABLE t
AS
WITH data AS (
SELECT...
)
SELECT *
FROM data

Related

Why do i receive 'Duplicate column name' error when innerjoin-ing 2 tables with similar column name?

CREATE TABLE student_activestudent AS
(
SELECT *
FROM
student
INNER JOIN
activestudent ON activestudent.studentnumber=student.studentnumber
);
I am expecting a table with 2 columns of studentnumber but I received Duplicate error instead --> Duplicate column name 'studentnumber'
A database table must have unique column names.
When you do select * you will get all columns from all tables and studentnumber exists on both student table and activestudent table. So to solve you problem specify the columns you want instead of *
CREATE TABLE student_activestudent AS
(
SELECT
student.studentnumber,
..Other columns..
FROM
student
INNER JOIN
activestudent ON activestudent.studentnumber=student.studentnumber
);
At the very least, studentnumber is duplicated. In general, I strongly recommend that a view list all the columns explicitly. This protects the view if underlying columns change.
That said, if studentnumber is the only column, then you can do:
CREATE TABLE student_activestudent AS
SELECT *
FROM student s JOIN
activestudent ast
USING (studentnumber);
With using, the * does not repeat the join keys.
You cannot select two tables that have same column's name.
The best way is not to select *
Select by column and if the column is same you can put [as]
Example
SELECT student.studentnumber as stuNumber, activestudent.studentnumber as actstuNumber

Select / Merge user specific rows with additional fallback rows in PostgreSQL

Setup: Postgresql table with a customer_id and a request_id column (+ additional not relevant data).
The rows with customer_id set to NULL work as a fallback/default.
Example what the table looks like:
Goal: I want to select all rows from the table for a given customer (e.g. where customer_id = 2).
For any existent request_id: If there are no entries for the given customer, return the fallback rows (where customer is null).
So the result should look like this:
Any idea how to write the select statement for postgresql? I'm kind of stuck and couldn't really find anything helpful so far. Thanks!
This is a strange requirement.
select t.*
from t
where t.customer_id = 2 or
(t.customer_id is null and
not exists (select 1 from t t2 where t2.request_id = t.request_id and t2.customer_id = 2)
);
For performance, I would recommend an index on (request_id, customer_id).

Create a field in Firebird which displays data from another table

I didn't find a working solution for creating a "lookup column" in a Firebird database.
Here is an example:
Table1: Orders
[OrderID] [CustomerID] [CustomerName]
Table2: Customers
[ID] [Name]
When I run SELECT * FROM ORDERS I want to get OrderID, CustomerID and CustomerName....but CustomerName should automatically be computed by looking for the "CustomerID" in the "ID" column of "Customer" Table, returning the content of the "Name" column.
Firebird has calculated fields (generated always as/computed by), and these allow selecting from other tables (contrary to an earlier version of this answer, which stated that Firebird doesn't support this).
However, I suggest you use a view instead, as I think it performs better (haven't verified this, so I suggest you test this if performance is important).
Use a view
The common way would be to define a base table and an accompanying view that gathers the necessary data at query time. Instead of using the base table, people would query from the view.
create view order_with_customer
as
select orders.id, orders.customer_id, customer.name
from orders
inner join customer on customer.id = orders.customer_id;
Or you could just skip the view and use above join in your own queries.
Alternative: calculated fields
I label this as an alternative and not the main solution, as I think using a view would be the preferable solution.
To use calculated fields, you can use the following syntax (note the double parentheses around the query):
create table orders (
id integer generated by default as identity primary key,
customer_id integer not null references customer(id),
customer_name generated always as ((select name from customer where id = customer_id))
)
Updates to the customer table will be automatically reflected in the orders table.
As far as I'm aware, the performance of this option is less than when using a join (as used in the view example), but you might want to test that for yourself.
FB3+ with function
With Firebird 3, you can also create calculated fields using a trigger, this makes the expression itself shorter.
To do this, create a function that selects from the customer table:
create function lookup_customer_name(customer_id integer)
returns varchar(50)
as
begin
return (select name from customer where id = :customer_id);
end
And then create the table as:
create table orders (
id integer generated by default as identity primary key,
customer_id integer not null references customer(id),
customer_name generated always as (lookup_customer_name(customer_id))
);
Updates to the customer table will be automatically reflected in the orders table. This solution can be relatively slow when selecting a lot of records, as the function will be executed for each row individually, which is a lot less efficient than performing a join.
Alternative: use a trigger
However if you want to update the table at insert (or update) time with information from another table, you could use a trigger.
I'll be using Firebird 3 for my answer, but it should translate - with some minor differences - to earlier versions as well.
So assuming a table customer:
create table customer (
id integer generated by default as identity primary key,
name varchar(50) not null
);
with sample data:
insert into customer(name) values ('name1');
insert into customer(name) values ('name2');
And a table orders:
create table orders (
id integer generated by default as identity primary key,
customer_id integer not null references customer(id),
customer_name varchar(50) not null
)
You then define a trigger:
create trigger orders_bi_bu
active before insert or update
on orders
as
begin
new.customer_name = (select name from customer where id = new.customer_id);
end
Now when we use:
insert into orders(customer_id) values (1);
the result is:
id customer_id customer_name
1 1 name1
Update:
update orders set customer_id = 2 where id = 1;
Result:
id customer_id customer_name
1 2 name2
The downside of a trigger is that updating the name in the customer table will not automatically be reflected in the orders table. You would need to keep track of these dependencies yourself, and create an after update trigger on customer that updates the dependent records, which can lead to update/lock conflicts.
No need here a complex lookup field.
No need to add a persistant Field [CustomerName] on Table1.
As Gordon said, a simple Join is enough :
Select T1.OrderID, T2.ID, T2.Name
From Customers T2
Join Orders T1 On T1.IDOrder = T2.ID
That said, if you want to use lookup Fields (as we do it on a Dataset) with SQL you can use some thing like :
Select T1.OrderID, T2.ID,
( Select T3.YourLookupField From T3 where (T3.ID = T2.ID) )
From Customers T2 Join Orders T1 On T1.IDOrder = T2.ID
Regards.

Unique constraint on Distinct select in Oracle database

I have a data processor that would create a table from a select query.
<_config:table definition="CREATE TABLE TEMP_TABLE (PRODUCT_ID NUMBER NOT NULL, STORE NUMBER NOT NULL, USD NUMBER(20, 5),
CAD NUMBER(20, 5), Description varchar(5), ITEM_ID VARCHAR(256), PRIMARY KEY (ITEM_ID))" name="TEMP_TABLE"/>
and the select query is
<_config:query sql="SELECT DISTINCT ce.PRODUCT_ID, ce.STORE, op.USD ,op.CAD, o.Description, ce.ITEM_ID
FROM PRICE op, PRODUCT ce, STORE ex, OFFER o, SALE t
where op.ITEM_ID = ce.ITEM_ID and ce.STORE = ex.STORE
and ce.PRODUCT_ID = o.PRODUCT_ID and o.SALE_ID IN (2345,1234,3456) and t.MEMBER = ce.MEMBER"/>
When I run that processor, I get an unique constraint error, though I have a distinct in my select statement.
I tried with CREATE TABLE AS (SELECT .....) its creating fine.
Is it possible to get that error? I'm doing a batch execute so not able to find the individual record.
The select distinct applies to the entire row, not to each column individually. So, two rows could have the same value of item_id but be different in the other columns.
The ultimate fix might be to have a group by item_id in the query, instead of select distinct. That would require other changes to the logic. Another possibility would be to use row_number() in a subquery and select the first row.

how to transform vertical fields in a table to horizontal result by SQL

I have a table like this:
create table t1 {
person_id int,
item_name varchar(30),
item_value varchar(100)
};
Suppose person_id+item_name is the composite key, now I have some data (5 records) in table t1 as below:
person_id ====item_name ====== item_value
1 'NAME' 'john'
1 'GENDER' 'M'
1 'DOB' '1970/02/01'
1 'M_PHONE' '1234567890'
1 'ADDRESS' 'Some Addresses unknown'
Now I want to use SQL (or combing store procedure/function or whatever) to query the above result (1 result set) become:
NAME==GENDER==DOB========M_PHONE=======ADDRESS===============
1 M 1970/02/01 1234567890 Some Addresses unknown
How should I do ?
Thank you for your help.
Regardless of the database you are using, the concept of what you are trying to achieve is called "Pivot Table".
Here's an example for mysql:
http://en.wikibooks.org/wiki/MySQL/Pivot_table
Some databases have builtin features for that, see the links below.
SQLServer:
http://msdn.microsoft.com/de-de/library/ms177410.aspx
Oracle:
http://www.dba-oracle.com/t_pivot_examples.htm
You can always create a pivot by hand. Just select all the aggregations in a result set and then select from that result set. Note, in your case, you can put all the names into one column using concat (i think that's group_concat in mysql), since you cannot know how many names are related to a person_id.
Finally, I found the solution in PostgreSQL:
select * from crosstab ('select person_id, item_name, item_value from t1 where person_id = 1 ')
as virtual_table ( person_id integer, name varchar, gender varchar, dob varchar, m_phone varchar, address varchar)
Also need to install the crosstab function on Postgres. See more: http://www.postgresql.org/docs/8.3/static/tablefunc.html