SQL Insert rows into table that must have 2 distinct columns but also one non distinct column - sql

I have two tables, a promotion table and a prize table.
CREATE TABLE PRIZE(
PRIZEID INT NOT NULL PRIMARY KEY,
COST DOUBLE NOT NULL,
PRIZENAME VARCHAR(100) NOT NULL,
)
CREATE TABLE PROMOTION (
PROMOTIONID INTEGER NOT NULL,
LEVEL INTEGER NOT NULL,
AMOUNT NOT NULL,
COST DOUBLE NOT NULL DEFAULT 0,
PRIZENAME VARCHAR(100) NOT NULL DEFAULT ' ',
PRIZEID INTEGER
)
The prize table is currently empty and I want to copy records from the promotion table into the prize table. in doing this I only want to select those records that have unique values in two columns, the prizename and the cost. I will be dropping those columns from promotion afterwards.
Right now I have the following sql statement
INSERT INTO prize(PRIZEID, COST, PRIZENAME)
SELECT r.PRIZEID, r.COST, r.PRIZENAME
FROM PROMOTION r;
but this will insert all records into the prize table. I realize I can use the distinct keyword in the select to select unique instances of cost and prizename but in my case the prizeid will always be unique and since the distinct keyword applies to all columns in the select clause it won't help.
Thanks in advance!

You'll have to just replace the PRIZEID value with new ones. Because it sounds like you currently have duplicates on your PROMOTION table
First add all the distinct PRIZENAMEs and COSTs to your new PRIZE table:
INSERT INTO prize(PRIZEID, COST, PRIZENAME)
SELECT DISTINCT (SELECT MAX(PRIZEID)+1 FROM PRIZE), r.COST, r.PRIZENAME
FROM PROMOTION r;
Then update your PROMOTIONs table with the new PRIZEID
UPDATE PROMOTION R
SET R.PRIZEID =
(SELECT P.PRIZEID
FROM PRIZE
WHERE P.PRIZENAME=R.PRIZENAME
AND P.COST=R.COST);
Then, I think from there you can safely delete the columns from your PROMOTIONs table

This will get the unique prizes based on prizename and cost and get the lowest prizeid for the group.
INSERT INTO prize(PRIZEID, COST, PRIZENAME)
SELECT MIN(r.PRIZEID), r.COST, r.PRIZENAME
FROM PROMOTION r
GROUP BY r.COST, r.PRIZENAME
;

Related

How do I insert data from one table to another when there is unequal number of rows in one another?

I have a table named People that has 19370 rows with playerID being the primary column. There is another table named Batting, which has playerID as a foreign key and has 104324 rows.
I was told to add a new column in the People table called Total_HR, which is included in the Batting table. So, I have to insert that column data from the Batting table into the People table.
However, I get the error:
Msg 515, Level 16, State 2, Line 183 Cannot insert the value NULL into
column 'playerID', table 'Spring_2019_BaseBall.dbo.People'; column
does not allow nulls. INSERT fails. The statement has been terminated.
I have tried UPDATE and INSERT INTO SELECT, however got the same error
insert into People (Total_HR)
select sum(HR) from Batting group by playerID
I expect the output to populate the column Total_HR in the People table using the HR column from the Batting table.
You could use a join
BEGIN TRAN
Update People
Set Total_HR = B.HR_SUM
from PEOPLE A
left outer join
(Select playerID, sum(HR) HR_SUM
from Batting
group by playerID) B on A.playerID = B.playerID
Select * from People
ROLLBACK
Notice that I've put this code in a transaction block so you can test the changes before you commit
From the error message, it seems that playerID is a required field in table People.
You need to specify all required fields of table People in the INSERT INTO clause and provide corresponding values in the SELECT clause.
I added field playerID below, but you might need to add additional required fields as well.
insert into People (playerID, Total_HR)
select playerID, sum(HR) from Batting group by playerID
It is strange, however, that you want to insert rows in a table that should already be there. Otherwise, you could not have a valid foreign key on field playerID in table Batting... If you try to insert such rows from table Batting into table People, you might get another error (violation of PRIMARY KEY constraint)... Unless... you are creating the database just now and you want to populate empty table People from filled/imported table Batting before adding the actual foreign key constraint to table People. Sorry, I will not question your intentions. I personally would consider to update the query somewhat so that it will not attempt to insert any rows that already exist in table People:
insert into People (playerID, Total_HR)
select Batting.playerID, sum(Batting.HR)
from Batting
left join People on People.playerID = Batting.playerID
where People.playerID is null and Batting.playerID is not null
group by playerID
You need to calculate the SUM and then join this result to the People table to bring into the same rows both Total_HR column from People and the corresponding SUM calculated from Batting.
Here is one way to write it. I used CTE to make is more readable.
WITH
CTE_Sum
AS
(
SELECT
Batting.playerID
,SUM(Batting.HR) AS TotalHR_Src
FROM
Batting
GROUP BY
Batting.playerID
)
,CTE_Update
AS
(
SELECT
People.playerID
,People.Total_HR
,CTE_Sum.TotalHR_Src
FROM
CTE_Sum
INNER JOIN People ON People.playerID = CTE_Sum.playerID
)
UPDATE CTE_Update
SET
Total_HR = TotalHR_Src
;

Query trying to select but get ambiguous error?

It runs but I select all the columns. Can someone explain to me why my first query doesn't work? I don't think I need a join. If I can get some help that would be good. To be quite honest I've never seen the error before. If it works with SELECT*, I don't understand why I have issues with select specific columns.
These are my tables:
create table product
(
pdt# varchar(10) not null,
pdt_name varchar(30) not null,
pdt_label varchar(30) not null,
constraint product_pk primary key (pdt#));
create table orders
(
pdt# varchar(10) not null,
qty number(11,0) not null,
city varchar(30) not null
);
And these are the values
insert into product values ([111,chair,chr]);
insert into product values ([222,stool,stl]);
insert into product values ([333,table,tbl]);
insert into orders values ([111,22,Ottawa]);
insert into orders values ([222,22,Ottawa]);
insert into orders values ([333,22,Toronto]);
Question is this:
c. List all [pdt#,pdt_name,qty] when the order is from [Ottawa]
I tried:
SELECT pdt#, pdt_name, qty FROM orders, product WHERE city='Ottawa';
I get column is ambiguously defined error. But when I run:
SELECT *, qty FROM orders, product WHERE city='Ottawa';
It runs but I select all the columns. Can someone explain to me why my first query doesn't work? I don't think I need a join. If I can get some help that would be good. To be quite honest I've never seen the error before. If it works with SELECT*, I don't understand why I have issues with select specific columns.
This is because both the tables have pdt# in common and you are selecting it in your query. In cases like these, you have to explicitly specify the table from which the column should be picked up.
You should also join the tables. Else you would get a cross-joined result.
SELECT p.pdt#, p.pdt_name, o.qty
FROM orders o join product p on o.pdt# = p.pdt#
WHERE o.city='Ottawa';
Your second query works because you are selecting all the columns from both the tables and ideally it should not be done. Always specify the columns you need when you are selecting from more than one table.

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 insert values from column A of table X to column B of table Y - and order them randomly

I need to collect the values from the column "EmployeeID" of the table "Employees" and insert them into the column "EmployeeID" of the table "Incident".
At the end, the Values in the rows of the column "EmployeeID" should be arranged randomly.
More precisely;
I created 10 employees with their ID's, counting from 1 up to 10.
Those Employees, in fact the ID's, should receive random Incidents to work on.
So ... there are 10 ID's to spread on all Incidents - which might be 1000s.
How do i do this?
It's just for personal exercise on the local maschine.
I googled, but didn't find an explicit answer to my problem.
Should be simple to solve for you champs. :)
May anyone help me, please?
NOTES:
1) I've already created a column called "EmployeeID" in the table "Incident", therefore I'll need an update statement, won't I?
2) Schema:
[dbo].[EmployeeType]
[dbo].[Company]
[dbo].[Division]
[dbo].[Team]
[dbo].[sysdiagrams]
[dbo].[Incident]
[dbo].[Employees]
3) 1. Pre-solution:
CREATE TABLE IncidentToEmployee
(
IncidentToEmployeeID BIGINT IDENTITY(1,1) NOT NULL,
EmployeeID BIGINT NULL,
Incident FLOAT NULL
PRIMARY KEY CLUSTERED (IncidentToEmployeeID)
)
INSERT INTO IncidentToEmployee
SELECT
EmployeeID,
Incident
FROM dbo.Employees,
dbo.Incident
ORDER BY NEWID()
SELECT * FROM IncidentToEmployee
GO
3) 2. Output by INNER JOIN ON
In case you are wondering about the "Alias" column;
Nobody really knows which persons are behind the ID's - that's why I used an Alias column.
SELECT Employees.Alias,
IncidentToEmployee.Incident
FROM Employees
INNER JOIN
IncidentToEmployee ON
Employees.EmployeeID = IncidentToEmployee.EmployeeID
ORDER BY Alias
4) Final Solution
As I mentioned, I added at first a column called "EmployeeID" already to my "Incident" table. That's why I couldn't use an INSERT INTO statement at first and had to use an UPDATE statement. I found the most suitable solution now - without creating a new table as I did as a pre-solution.
Take a look at the following code:
ALTER Table Incident
ADD EmployeeID BIGINT NULL
UPDATE Incident
SET Incident.EmployeeID = EmployeeID
FROM Incident INNER JOIN Employees
ON Incident = EmployeeID
SELECT
EmployeeID,
Incident
FROM dbo.Employees,
dbo.Incident
ORDER BY NEWID()
Thank you all for your help - It took way longer to find a solution as I thought it would take; but I finally made it. Thanks!
UPDATE
I think you need to allocate different task to different user, a better approach will be to create a new table let's say EmployeeIncidents having columns Id(primary) , EmployeeID and IncidentID .
Now you can insert random EmployeesID and random IncidentID to new table, this way you will be able to keep records also ,
Updating Incident table will not be a smart choice.
INSERT INTO EmployeeIncidents
SELECT TOP ( 10 )
EmployeesID ,
IncidentID
FROM dbo.Employees,
dbo.Incident
ORDER BY NEWID()
Written by hand, so may need to tweak syntax, but something like this should do it. The Rand() function will give the same value unless seeded, so you can see with something like date to get randomness.
Insert Into Incidents
Select Top 10
EmployeeID
From Employees
Order By
Rand(GetDate())

Underlying rows in Group By

I have a table with a certain number of columns and a primary key column (suppose OriginalKey). I perform a GROUP BY on a certain sub-set of those columns and store them in a temporary table with primary key (suppose GroupKey). At a later stage, I may need to get more details about one or more of those groupings (which can be found in the temporary table) i.e. I need to know which were the rows from the original table that formed that group. Simply put, I need to know the mappings between GroupKey and OriginalKey. What's the best way to do this? Thanks in advance.
Example:
Table Student(
StudentID INT PRIMARY KEY,
Level INT, --Grade/Class/Level depending on which country you are from)
HomeTown TEXT,
Gender CHAR)
INSERT INTO TempTable SELECT HomeTown, Gender, COUNT(*) AS NumStudents FROM Student GROUP BY HomeTown, Gender
On a later date, I would like to find out details about all towns that have more than 50 male students and know details of every one of them.
How about joining the 2 tables using the GroupKey, which, you say, are the same?
Or how about doing:
select * from OriginalTable where
GroupKey in (select GroupKey from my_temp_table)
You'd need to store the fields you grouped on in your temporary table, so you can join back to the original table. e.g. if you grouped on fieldA, fieldB, and fieldC, you'd need something like:
select original.id
from original
inner join temptable on
temptable.fieldA = original.fieldA and
temptable.fieldB = original.fieldB and
temptable.fieldC = original.fieldC