I have three tables
Node
- NodeID
Role
- RoleID
NodeRoles
- NodeID
- RoleID
For every record in NodeID I'd like to create a record in NodeRoles against every record in table Role.
this was my attempt at solving the above.
INSERT INTO NodeRoles (NodeID, RoleID)
VALUES ( SELECT NodeID from Node, SELECT RoleID from Role )
This seems like a simple approach and the idea feels right, but the error that comes back is that we're reporting multiple values into a singluar column. Which reviewing that makes sense as that's exactly what is happening.
In application code I would simply set up two foreach loops, but I'm not sure how to get the same thing in SQL. Thank you!
Try this:
INSERT INTO NodeRoles (NodeID, RoleID)
( SELECT NodeID,RoleID from Node,Role )
Related
I’m trying to create a trigger to change the value of a column in table B if it finds the information in a column in table A.
An example of my database is below:
[TableA],
itemID
[TableB],
itemID
itemInStock
Once a user creates an entry in Table A declaring an itemID, the trigger needs to change the TableB.itemInStock column to ‘Yes’
I’m still learning SQL so excuse me if I’ve missed something, let me know if you need any more info.
I understand there are better ways of doing this but I've been told I need to do this using a trigger.
I've attempted a few different things, but as it stands nothing is working, below is the current solution I have however this updates all itemInStock rows to 'Yes', where as I only want the ones to update where the TableB.itemID matches the itemID entered in TableA.
ALTER TRIGGER [itemAvailability] ON [dbo].[TableA] FOR
INSERT
AS
BEGIN
UPDATE [dbo].[TableB] set itemInStock = 'Yes' WHERE
TableB.itemID = itemID
END
Two problems -
you're not looking at the Inserted pseudo table which contains the
newly inserted rows
you're assuming the trigger is called once per row - this is not the
case, the trigger is called once per statement and the Inserted
pseudo table will contain multiple rows - and you need to deal with
that
So, your code should look like this -
ALTER TRIGGER [itemAvailability] ON [dbo].[TableA]
FOR INSERT
AS
UPDATE TB
SET itemInStock = 'Yes'
FROM [dbo].[TableB] TB JOIN inserted I
on TB.itemID = I.itemID
In a SQL Server database that I am setting up, there are a few 1 to many tables that I would like to create the "many" table records after the parent record is inserted, inserting only the auto generated ID value and another value from the parent record.
For instance:
Table 1 (Parent): Auto_ID, Name, createby, createdatetime
Table 2 (Child): Auto_ID, Parent_Auto_ID, Col1, Col2, createby, createdatetime
Table 3 (Child): Parent_Auto_ID, Col1, createby, createdatetime
I already have:
CREATE TRIGGER [dbo].[ipamuserInsert]
ON [dbbo].[ipamuser]
FOR INSERT
AS
SET NOCOUNT ON
INSERT INTO [dbo].[ipamuserdefault]
(ipamuserID, homepage, createby, createdatetime)
VALUES
SELECT
ipamuserID,
NULL,
createby,
GETDATE()
FROM
inserted
INSERT INTO [dbo].[ipamextlink]
(ipamuserID, link, createby, GETDATE())
VALUES
SELECT
ipamuserID, null, createby, GETDATE()
FROM
inserted
GO
Is this the right syntax, or do I need to declare a separate temp variable and store the ipamuserID and the createby values and use those instead?
I cant test this without your table definitions but I think that you are spot on.
Depending on the number of tables involved I would consider making this dynamic. The number of tables would have to be high to make it worth the effort though.
Editbased on comment:
You can make this dynamic by using system views to find out what tables are related and generate your Sql dynamically based on the metadata. Here are a couple articles to get you started.
https://msdn.microsoft.com/en-us/library/ms186778.aspx
https://msdn.microsoft.com/en-us/library/ms177862.aspx
The basic structure would be to create a cursor loop for each related table and an inner cursor loop for each column in the related table. You would build the sql statement dynamically in the same format as you have it defined in your question.
I have two table "Container" and "Control". These are existing tables and there is no foreign key relationship between the two. These are also very old tables so are not normalized. And I cannot change the structure now.
Below is the structure of the two tables.
Container table :
Control Table :
The Name field in Control table contains CTableName+CPName from Container table.
I want to update the columnName field of Control table with the value of CID column of Container table. and also want to insert one more record (for ctable2 i.e the fourth row in final Control table below) in Control table.
The tablename and columnname columns have will always be have default values.
The final Control table should look like this:
How do I do this?
I hope you want to apply this fix because you want normalize your table structure.
Try this:
First step:
In this way you'll UPDATE all Control rows with the value of Container table where the couple fields CTableName and CPName are the same of Name (excluding the rows of Container with the same couple fields)
UPDATE Control
SET ColumnValue = (
SELECT c.CID
FROM Container c
WHERE c.CTableName + '+' + c.CPName = Control.Name
AND NOT EXISTS(
SELECT 'PREVIOUS'
FROM Container c2
WHERE c.CTableName = c2.CTableName
AND c.CPName = c2.CPName
AND c.CID < c2.CID
)
),
TableName = 'default', ColumnName = 'default'
WHERE ColumnValue IS NULL
Second step:
Adding elements don't present in Control table
INSERT INTO Control (field list)
SELECT field list
FROM Container co
WHERE NOT EXISTS(
SELECT 'in_control'
FROM Control ct
WHERE co.CID = ct.ColumnValue
)
After these two steps you can drop column Name in Control table
I am an Oracle plsql programmer and worked with Sql-server as well.
First you should describe the relationship between the 2 tables, in the end i could figger it out but it's better you explain it yourself.
To update a table with information from another table you should ask yourself:
- when should the update take place?
- what are the conditions to start the update?
- how should the update be done?
In Oracle there is a database object called a trigger. It's quite a handy object and probably just what you need. I believe that sql-server has it too.
Pls fee free to ask any questions but do read the sql-server appropriate manual as well.
Good luck, Edward.
I have a table that holds organization data. I also have a new table that is going to hold info about shipping containers.
As an initial test I want to populate the new Shipping_Containers table by giving one container to each organization.
So I thought about getting the organization ids and looping through them and doing an insert into Shipping_Containers for each organization id, something like this:
select * into #orgs from Organization_1
while (select id from #orgs ) IS NOT NULL
begin
insert into Shipping_Containers (name, org)
values('test_name', id)
end
I know there is probably a lot wrong with that but firstly it is giving this error:
Msg 207, Level 16, State 1, Line 4
Invalid column name 'id'.
I'm using SQL Server 2008 R2 and I'm new to T-SQL so any guidance here would be appreciated, thanks.
Try
INSERT INTO Shipping_Containers (name, org)
SELECT 'test_name', id
FROM Organization_1
Due to non-disclosure at my work, I have created an analogy of the situation. Please try to focus on the problem and not "Why don't you rename this table, m,erge those tables etc". Because the actual problem is much more complex.
Heres the deal,
Lets say I have a "Employee Pay Rise" record that has to be approved.
There is a table with single "Users".
There are tables that group Users together, forexample, "Managers", "Executives", "Payroll", "Finance". These groupings are different types with different properties.
When creating a "PayRise" record, the user who is creating the record also selects both a number of these groups (managers, executives etc) and/or single users who can 'approve' the pay rise.
What is the best way to relate a single "EmployeePayRise" record to 0 or more user records, and 0 or more of each of the groupings.
I would assume that the users are linked to the groups? If so in this case I would just link the employeePayRise record to one user that it applies to and the user that can approve. So basically you'd have two columns representing this. The EmployeePayRise.employeeId and EmployeePayRise.approvalById columns. If you need to get to groups, you'd join the EmployeePayRise.employeeId = Employee.id records. Keep it simple without over-complicating your design.
My first thought was to create a table that relates individual approvers to pay rise rows.
create table pay_rise_approvers (
pay_rise_id integer not null references some_other_pay_rise_table (pay_rise_id),
pay_rise_approver_id integer not null references users (user_id),
primary key (pay_rise_id, pay_rise_approver_id)
);
You can't have good foreign keys that reference managers sometimes, and reference payroll some other times. Users seems the logical target for the foreign key.
If the person creating the pay rise rows (not shown) chooses managers, then the user interface is responsible for inserting one row per manager into this table. That part's easy.
A person that appears in more than one group might be a problem. I can imagine a vice-president appearing in both "Executive" and "Finance" groups. I don't think that's particularly hard to handle, but it does require some forethought. Suppose the person who entered the data changed her mind, and decided to remove all the executives from the table. Should an executive who's also in finance be removed?
Another problem is that there's a pretty good chance that not every user should be allowed to approve a pay rise. I'd give some thought to that before implementing any solution.
I know it looks ugly but I think somethimes the solution can be to have the table_name in the table and a union query
create table approve_pay_rise (
rise_proposal varchar2(10) -- foreign key to payrise table
, approver varchar2(10) -- key of record in table named in other_table
, other_table varchar2(15) );
insert into approve_pay_rise values ('prop000001', 'e0009999', 'USERS');
insert into approve_pay_rise values ('prop000001', 'm0002200', 'MANAGERS');
Then either in code a case statement, repeated statements for each other_table value (select ... where other_table = '' .. select ... where other_table = '') or a union select.
I have to admit I shudder when I encounter it and I'll now go wash my hands after typing a recomendation to do it, but it works.
Sounds like you'd might need two tables ("ApprovalUsers" and "ApprovalGroups"). The SELECT statement(s) would be a UNION of UserIds from the "ApprovalUsers" and the UserIDs from any other groups of users that are the "ApprovalGroups" related to the PayRiseId.
SELECT UserID
INTO #TempApprovers
FROM ApprovalUsers
WHERE PayRiseId = 12345
IF EXISTS (SELECT GroupName FROM ApprovalGroups WHERE GroupName = "Executives" and PayRiseId = 12345)
BEGIN
SELECT UserID
INTO #TempApprovers
FROM Executives
END
....
EDIT: this would/could duplicate UserIds, so you would probably want to GROUP BY UserID (i.e. SELECT UserID FROM #TempApprovers GROUP BY UserID)