How to create a table with multiple columns - sql

Struggling with a create table statement which is based on this select into statement below:
#MaxAPDRefundAmount money = 13.00
...
select pkd.*, pd.ProviderReference, per.FirstName, per.Surname, #MaxAPDRefundAmount [MaxAPDRefundAmount],commission.Type [Commission] into #StagedData from CTE_PackageData pkd
inner join J2H.dbo.Package pk on pkd.Reference = pk.Reference
inner join J2H.dbo.Product pd on pk.PackageId = pd.PackageId
inner join J2H.dbo.FlightReservation fr on pd.ProductId = fr.ProductId
and fr.FlightBoundID = 1
inner join J2H.dbo.ProductPerson pp on pd.ProductId = pp.ProductID
and pp.StatusId < 7
inner join J2H.dbo.Flight f on fr.FlightId = f.FlightID
inner join J2H.dbo.Person per on pk.PackageId = per.PackageId
and per.PersonId = pp.PersonId
inner join J2H.dbo.PersonType pt on per.PersonTypeId = pt.PersonTypeID
We are changing a select into to just normal insert and select, so need a create table (we are going to create a temp (hash tag table) and not declaring a variable table. Also there is a pkd.* at the start as well so I am confused in knowing which fields to include in the create table. Do I include all the fields in the select statement into the create statement?
Update:
So virtually I know I need to include the data types below but I can just do:
create table #StagedData
(
pkd.*,
pd.ProviderReference,
per.FirstName,
per.Surname,
#MaxAPDRefundAmount [MaxAPDRefundAmount],
commission
)

"Do I include all the fields in the select statement into the create statement?" Well, that depends, if you need them, than yes, if not than no. It's impossible for us to say whether you need them... If you're running this exact query as insert, than yes.
As for the create statement, you can run the query you have, but replace into #StagedData with something like into TEMP_StagedData. In management studio you can let sql server build the create query for you: right-click the newly created TEMP_StagedData table in the object explorer (remember to refresh), script Table as, CREATE To and select New Query Editor Window.

The documentation of the CREATE TABLE statement is pretty straightforward.
No. Clearly, you cannot use pkd.* in a create table statement.
What you can do is run your old SELECT INTO statement as a straight SELECT (remove the INTO #stagedata) part, and look at the columns that get returned by the SELECT.
Then write a CREATE TABLE statement that includes those columns.

To create a table from a SELECT without inserting data, add a WHERE clause that never returns True.
Like this:
SELECT * INTO #TempTable FROM Table WHERE 1=0
Once the table with the columns for your SELECT, you can add additional columns with ALTER TABLE.
ALTER TABLE #TempTable ALL ExtraColumn INT
Then do your INSERT/SELECT.

Related

SQL Left join on different columns considering specific conditions

I believe this is an easy one. Just getting started on SQL, so I am finding it a bit tricky. So I am using SQL on SAS, and I want to join two tables but on different columns based on a value of a column. Practical example:
Proc sql;
create table new_table_name as select
a.proposal_code as new_name_proposal_code,
a.1st_client_code as new_name_1st_client_code,
a.2nd_client_code as new_name_2nd_client_code,
a.3rd_client_code as new_name_3rd_client_code,
a.4th_client_code as new_name_4th_client_code,
a.product_type as new_name_product_type,
b.2nd_client_code
from existing_table a
left join existing table b (on b.2nd_client_code=a.2nd_client_code and a.product_type = "clothes") or
left join existing table b (on b.2nd_client_code=a.3rd_client_code and (a.product_type = "cars" or a.product_type = "bikes"));
quit;
So this is the code that I'm using at the moment, and the goal is to join table a and table b using b.2nd client code = a.2nd client code if the product type from table a is = to "clothes", and if the product type from table a is either "cars" or "bikes", join table a and table b using b.2nd client code = a.3rd client code. Basically, look at two different "on's" regarding the specific product type. When joining these two tables, if one row has product type "clothes", I want it to look at the 2nd client code, if it is either "cars" or "bikes", look at the 3rd client code.
Hope I made it clear. The error I am getting at the moment is "expecting an on". Is it a problem of syntax?
Yes. The parentheses before the on is not correct. Your query has other issues as well. I think you want:
create table new_table_name as
select a.proposal_code as new_name_proposal_code,
a.1st_client_code as new_name_1st_client_code,
a.2nd_client_code as new_name_2nd_client_code,
a.3rd_client_code as new_name_3rd_client_code,
a.4th_client_code as new_name_4th_client_code,
a.product_type as new_name_product_type,
coalsesce(bc.2nd_client_code, bcb.2nd_client_code)
from existing_table a left join
existing_table bc
on bc.2nd_client_code = a.2nd_client_code and
a.product_type = 'clothes' left join
existing_table bcb
on bcb.2nd_client_code = a.3rd_client_code and
a.product_type in ('cars', 'bikes');
Notes:
No parentheses before the on clause.
No or left join. or is a boolean operator. left join is an operator on sets (i.e. tables and results sets). The don't mix.
No repeated table aliases.
You want to combine the two code, so you need something like coalesce() in the select.
The SQL delimiter for strings is the single quote, not the double quote.
in is simpler than a string of or conditions.
Sounds like you just want a complex ON criteria and not two joins.
Something like this:
proc sql;
create table new_table_name as
select
a.proposal_code as new_name_proposal_code
,a.client_code1 as new_name_client_code1
,a.client_code2 as new_name_client_code2
,a.client_code3 as new_name_client_code3
,a.client_code4 as new_name_client_code4
,a.product_type as new_name_product_type
,b.client_code2 as new_name_other_client_code2
from tableA a
left join tableB b
on (b.client_code2=a.client_code2 and a.product_type = "clothes")
or (b.client_code2=a.client_code3 and a.product_type in ("cars","bikes"))
;
quit;
For a better answer post example inputs and desired output.

I'm having issues with the ALTER TABLE function

I'm attempting to use the tables trip, guide and reservation in order to make a normalized table. I'm getting the error "ORA-00933: SQL command not properly ended."
I'm not certain what is wrong with ALTER TABLE.
SELECT trip.TRIP_ID, trip.State, trip.Max_grp_size, trip.type, trip.season, guide.Guide_num, guide.last_name, guide.First_name, guide.address, guide.city, guide.Hire_date, trip_guides.guide_num, reservations.trip_price
FROM trip
JOIN trip_guides ON trip.TRIP_ID = trip_guides.trip_id
JOIN Guide ON trip_guides.guide_num = guide.Guide_num
ALTER TABLE trip ADD (price_trip CHAR)
JOIN reservations ON trip.price_trip = reservations.trip_price
ORDER BY trip.trip_ID;
It sounds like what you want is a "CREATE TABLE ... AS (SELECT...)" type of statement. Essentially creating a NEW table based on the result set of a SQL statement.
This would look like:
CREATE TABLE your_1st_level_normalized_table AS
(
SELECT trip.TRIP_ID,
trip.STATE,
trip.Max_grp_size,
trip.type,
trip.season,
guide.Guide_num,
guide.last_name,
guide.First_name,
guide.address,
guide.city,
guide.Hire_date,
trip_guides.guide_num,
reservations.trip_price,
NULL as PRICE_TRIP /*new field in the new table set to NULL*/
FROM trip
JOIN trip_guides ON trip.TRIP_ID = trip_guides.trip_id
JOIN Guide ON trip_guides.guide_num = guide.Guide_num
JOIN reservations ON trip.price_trip = reservations.trip_price
);
I've removed the ORDER BY since that's not allowed in this statement.

What if the column to be indexed is nvarchar data type in SQL Server?

I retrieve data by joining multiple tables as indicated on the image below. On the other hand, as there is no data in the FK column (EmployeeID) of Event table, I have to use CardNo (nvarchar) fields in order to join the two tables. On the other hand, the digit numbers of CardNo fields in the Event and Employee tables are different, I also have to use RIGHT function of SQL Server and this makes the query to be executed approximately 10 times longer. So, in this scene what should I do? Can I use CardNo field without changing its data type to int, etc (because there are other problem might be seen after changing it and it sill be better to find a solution without changing the data type of it). Here is also execution plan of the query below.
Query:
; WITH a AS (SELECT emp.EmployeeName, emp.Status, dep.DeptName, job.JobName, emp.CardNo
FROM TEmployee emp
LEFT JOIN TDeptA AS dep ON emp.DeptAID = dep.DeptID
LEFT JOIN TJob AS job ON emp.JobID = job.JobID),
b AS (SELECT eve.EventID, eve.EventTime, eve.CardNo, evt.EventCH, dor.DoorName
FROM TEvent eve LEFT JOIN TEventType AS evt ON eve.EventType = evt.EventID
LEFT JOIN TDoor AS dor ON eve.DoorID = dor.DoorID)
SELECT * FROM b LEFT JOIN a ON RIGHT(a.CardNo, 8) = RIGHT(b.CardNo, 8)
ORDER BY b.EventID ASC
You can add a computed column to your table like this:
ALTER TABLE TEmployee -- Don't start your table names with prefixes, you already know they're tables
ADD CardNoRight8 AS RIGHT(CardNo, 8) PERSISTED
ALTER TABLE TEvent
ADD CardNoRight8 AS RIGHT(CardNo, 8) PERSISTED
CREATE INDEX TEmployee_CardNoRight8_IDX ON TEmployee (CardNoRight8)
CREATE INDEX TEvent_CardNoRight8_IDX ON TEvent (CardNoRight8)
You don't need to persist the column since it already matches the criteria for a computed column to be indexed, but adding the PERSISTED keyword shouldn't hurt and might help the performance of other queries. It will cause a minor performance hit on updates and inserts, but that's probably fine in your case unless you're importing a lot of data (millions of rows) at a time.
The better solution though is to make sure that your columns that are supposed to match actually match. If the right 8 characters of the card number are something meaningful, then they shouldn't be part of the card number, they should be another column. If this is an issue where one table uses leading zeroes and the other doesn't then you should fix that data to be consistent instead of putting together work arounds like this.
This line is what is costing you 86% of the query time:
LEFT JOIN a ON RIGHT(a.CardNo, 8) = RIGHT(b.CardNo, 8)
This is happening because it has to run RIGHT() on those fields for every row and then match them with the other table. This is obviously going to be inefficient.
The most straightforward solution is probably to either remove the RIGHT() entirely or else to re-implement it as a built-in column on the table so it doesn't have to be calculated on the fly while the query is running.
While inserting the record, you would have to also insert the eight, right digits of the card number and store it in this field. My original thought was to use a computed column but I don't think those can be indexed so you'd have to use a regular column.
; WITH a AS (
SELECT emp.EmployeeName, emp.Status, dep.DeptName, job.JobName, emp.CardNoRightEight
FROM TEmployee emp
LEFT JOIN TDeptA AS dep ON emp.DeptAID = dep.DeptID
LEFT JOIN TJob AS job ON emp.JobID = job.JobID
),
b AS (
SELECT eve.EventID, eve.EventTime, eve.CardNoRightEight, evt.EventCH, dor.DoorName
FROM TEvent eve LEFT JOIN TEventType AS evt ON eve.EventType = evt.EventID
LEFT JOIN TDoor AS dor ON eve.DoorID = dor.DoorID
)
SELECT *
FROM b
LEFT JOIN a ON a.CardNoRightEight = b.CardNoRightEight
ORDER BY b.EventID ASC
This will help you see how to add a calculated column to your database.
create table #temp (test varchar(30))
insert into #temp
values('000456')
alter table #temp
add test2 as right(test, 3) persisted
select * from #temp
The other alternative is to fix the data and the data entry so that both columns are the same data type and contain the same leading zeros (or remove them)
Many thanks all of your help. With the help of your answers, I managed to reduce the query execution time from 2 minutes to 1 at the first step after using computed columns. After that, when creating an index for these columns, I managed to reduce the execution time to 3 seconds. Wow, it is really perfect :)
Here are the steps posted for those who suffers from a similar problem:
Step I: Adding computed columns to the tables (As CardNo fields are nvarchar data type, I specify data type of computed columns as int):
ALTER TABLE TEvent ADD CardNoRightEight AS RIGHT(CAST(CardNo AS int), 8)
ALTER TABLE TEmployee ADD CardNoRightEight AS RIGHT(CAST(CardNo AS int), 8)
Step II: Create index for the computed columns in order to execute the query faster:
CREATE INDEX TEmployee_CardNoRightEight_IDX ON TEmployee (CardNoRightEight)
CREATE INDEX TEvent_CardNoRightEight_IDX ON TEvent (CardNoRightEight)
Step 3: Update the query by using the computed columns in it:
; WITH a AS (
SELECT emp.EmployeeName, emp.Status, dep.DeptName, job.JobName, emp.CardNoRightEight --emp.CardNo
FROM TEmployee emp
LEFT JOIN TDeptA AS dep ON emp.DeptAID = dep.DeptID
LEFT JOIN TJob AS job ON emp.JobID = job.JobID
),
b AS (
SELECT eve.EventID, eve.EventTime, evt.EventCH, dor.DoorName, eve.CardNoRightEight --eve.CardNo
FROM TEvent eve
LEFT JOIN TEventType AS evt ON eve.EventType = evt.EventID
LEFT JOIN TDoor AS dor ON eve.DoorID = dor.DoorID)
SELECT * FROM b LEFT JOIN a ON a.CardNoRightEight = b.CardNoRightEight --ON RIGHT(a.CardNo, 8) = RIGHT(b.CardNo, 8)
ORDER BY b.EventID ASC

Postgres - CREATE TABLE FROM SELECT

I have two tables, one contains a large list of IDs and Info regarding those ids.
I have a second table Graph which just has two columns, each column contains the aforementioned id numbers, multiple times. I want to trim the size of my Info table by selecting only those ids that appear in my graph and creating a new smaller Info table. Is there a simple way of doing this?
CREATE TABLE FROM SELECT?
Thanks!
It's as easy as:
create table new_table
as
select t1.col1, t2.col2
from some_table t1
join t2 on t1.id = t2.some_id;
You can use any select statement for that. The column names of the new table are defined by the column aliases used in th query.
More details in the manual: http://www.postgresql.org/docs/current/static/sql-createtableas.html
You can create TEMP table if you need those small table only for that session. you can use below query to do that.
DROP TABLE IF EXISTS temp_table;
CREATE TEMP TABLE temp_table AS
SELECT
i.id as info_id, i.information as information
FROM
info i
INNER JOIN graph g ON i.id = g.id;
Now you can use this temp_table for your next table in the function.
OR
you can also create table like below (if you not want to create it as TEMP):
CREATE TABLE temp_table AS
SELECT
i.id as info_id, i.information as information
FROM
info i
INNER JOIN graph g ON i.id = g.id;

How to make multiple select into on the same table?

Hi i got a little problem right now i'm doing Stored Proc in sql server. I wanna get some result from multiple table and put it into a temporary table. So I thought i could use a "Select into" statement wich work fine until i decided to add multiple select into the temporary table. For example: Here's my code:
while #Compteur <= #wrhCodeEnd
select lp.lotQty ,lp.lotID into ZeTable from TB_lotLot ltlt
inner join TB_lotPal lp on ltlt.lotID=lp.lotID
inner join TB_palSuper ps ON lp.spID=ps.spID
inner join TB_expExpeditionLot eel ON eel.lotID=lp.spID
where ps.wrhID <> #Compteur and
ltlt.wrhID = #Compteur and
lp.lotID not in(select ZeTable.lotID from ZeTable)
the thing is I don't know if I can make multiple select into on the same temporary table and I also wanna check with a where clause the information in the table is not already there.
Thx in Advance
You can create temporary table and can use insert statement to add records with required columns and can drop it after use.