SQL server : Inserting/updating missing data from one table to another - sql-server

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.

Related

How to insert data into a table such that possible extra columns in data get added to the parent table?

I'm trying to insert daily imported data into a SQL Server (2017) table. While most of the time the imported data has a fixed amount of columns, sometimes the client wants to add a new column to the data-to-be-imported.
I'm seeking for a solution that when the data gets imported (whether it is from another table, from R or from .csv's, don't mind this), SQL would automatically add the missing (extra) column to the parent table, providing the column name and assigning NULL to all previous entries.
I've tried with both UNION ALL and BULK INSERT, but both of these require the same # of columns. I'm working with SSMS2017, R3.4.1.
Next, I tried with a staging table and modifying the UNION clause as:
SELECT * FROM Table_new
UNION ALL
SELECT Tp.*, '' FROM Table_parent Tp;
But more often than not the extra column doesn't occur, so the column dimension problem occurs again.
I also thought about running the queries from R with DBI and odbc dbWriteTable() and handling the invalid column error with TryCatch(), parsing the column name from the error message and so on, but this would be a shakiest craft I've ever done and would prefer not to.
Ultimately I thought adding an if clause in R, and depending on the number of added new columns, loop and add the ', ""' part to the SQL query to create the extra columns. I'm convinced that this is too complex solution to this problem.
# Pseudo-R
#calculate the difference between lenght(colnames)
diff <- diff(length(colnames_new, colnames_parent)
if diff = 0 {
dbQuery(BULK INSERT INTO old SELECT * FROM new;)
} else if diff > 0 {
dbQuery(paste0(SELECT * FROM new
UNION ALL
SELECT T1.*, loop_paste(, '' /* for every diff */), FROM parent T1;))
} else if diff < 0 {
dbQuery(SELECT * FROM parent
UNION ALL
SELECT T2.*, loop_paste(, '' /* for every diff */), FROM new T2;))
}
To summarize: when inserting data to SQL table, how to (automatically) append the columns in the parent table, when necessary? Thanks!
The things in your database such as tables, columns, primary keys, foreign keys, check clauses are all part of the database schema. People design the schema before adding data to the database.
If you want to add new columns then you have to redesign your schema. When you do this you will also have to rewrite some of the CRUD procedures.

SQL Server Trigger to alter different table

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

T-SQL Query for Setting Column Aliases

I'm after a way in SSMS of writing a query that will concatenate Table & Column to give me a much more readable Alias.
I'm actually using SSMS, right clicking on views in the object explorer, and selecting new view.
I select the tables I require from the list of available tables.
I then set the joins required in the SSMS diagram pane, and select all of the columns I want from the various tables.
In the criteria pane, I can see the Column, Alias, and Table columns.
It's fine all the time the value in the Column column is unique, for example:
Column = RequestedDeliveryDate
Alias = (blank)
Table = Stock Item
BUT!
As soon as the column value is NOT unique, SSMS assigns its own alias, for example:
Column = AddressLine1
Alias = Alias1
Table = Customer
Column = AddressLine1
Alias = Alias2
Table = Supplier
These are pretty hefty views that I'm dealing with, so SSMS assigns a lot of Aliases, which is not a problem in itself, but makes select statements in my Visual Studio project, much more unreadable:
SELECT RequestedDeliveryDate, Alias1, Alias2 FROM vwMyView
All that I'm after is some way in SSMS of writing a query that will concatenate Table & Column to give me a much more readable Alias:
Column = AddressLine1
Alias = CustomerAddressLine1
Table = Customer
Column = AddressLine1
Alias = SupplierAddressLine1
Table = Supplier
This would make my SELECT queries much more readable:
SELECT RequestedDeliveryDate,CustomerAddressLine1,SupplierAddressLine1 FROM vwMyView
I can manually assign an alias in the Criteria Pane, but it's very tedious across many views with many duplicate column names.
I hate the view designer. Just create the view with code only. Eg:
CREATE VIEW [dbo].[MyViewName]
AS
SELECT RequestedDeliveryDate,CustomerAddressLine1,SupplierAddressLine1 FROM vwMyView
GO
Copy the joins and filter from the view designer if you like, but then change the field aliasing in the SELECT section.

Merge query using two tables in SQL server 2012

I am very new to SQL and SQL server, would appreciate any help with the following problem.
I am trying to update a share price table with new prices.
The table has three columns: share code, date, price.
The share code + date = PK
As you can imagine, if you have thousands of share codes and 10 years' data for each, the table can get very big. So I have created a separate table called a share ID table, and use a share ID instead in the first table (I was reliably informed this would speed up the query, as searching by integer is faster than string).
So, to summarise, I have two tables as follows:
Table 1 = Share_code_ID (int), Date, Price
Table 2 = Share_code_ID (int), Share_name (string)
So let's say I want to update the table/s with today's price for share ZZZ. I need to:
Look for the Share_code_ID corresponding to 'ZZZ' in table 2
If it is found, update table 1 with the new price for that date, using the Share_code_ID I just found
If the Share_code_ID is not found, update both tables
Let's ignore for now how the Share_code_ID is generated for a new code, I'll worry about that later.
I'm trying to use a merge query loosely based on the following structure, but have no idea what I am doing:
MERGE INTO [Table 1]
USING (VALUES (1,23-May-2013,1000)) AS SOURCE (Share_code_ID,Date,Price)
{ SEEMS LIKE THERE SHOULD BE AN INNER JOIN HERE OR SOMETHING }
ON Table 2 = 'ZZZ'
WHEN MATCHED THEN UPDATE SET Table 1.Price = 1000
WHEN NOT MATCHED THEN INSERT { TO BOTH TABLES }
Any help would be appreciated.
http://msdn.microsoft.com/library/bb510625(v=sql.100).aspx
You use Table1 for target table and Table2 for source table
You want to do action, when given ID is not found in Table2 - in the source table
In the documentation, that you had read already, that corresponds to the clause
WHEN NOT MATCHED BY SOURCE ... THEN <merge_matched>
and the latter corresponds to
<merge_matched>::=
{ UPDATE SET <set_clause> | DELETE }
Ergo, you cannot insert into source-table there.
You could use triggers for auto-insertion, when you insert something in Table1, but that will not be able to insert proper Shared_Name - trigger just won't know it.
So you have two options i guess.
1) make T-SQL code block - look for Stored Procedures. I think there also is a construct to execute anonymous code block in MS SQ, like EXECUTE BLOCK command in Firebird SQL Server, but i don't know it for sure.
2) create updatable SQL VIEW, joining Table1 and Table2 to show last most current date, so that when you insert a row in this view the view's on-insert trigger would actually insert rows to both tables. And when you would update the data in the view, the on-update trigger would modify the data.

table relationships, SQL 2005

Ok I have a question and it is probably very easy but I can not find the solution.
I have 3 tables plus one main tbl.
tbl_1 - tbl_1Name_id
tbl_2- tbl_2Name_id
tbl_3 - tbl_3Name_id
I want to connect the Name_id fields to the main tbl fields below.
main_tbl
___________
tbl_1Name_id
tbl_2Name_id
tbl_3Name_id
Main tbl has a Unique Key for these fields and in the other table, fields they are normal fields NOT NULL.
What I would like to do is that any time when the record is entered in tbl_1, tbl_2 or tbl_3, the value from the main table shows in that field, or other way.
Also I have the relationship Many to one, one being the main tbl of course.
I have a feeling this should be very simple but can not get it to work.
Take a look at SQL Server triggers. This will allow you to perform an action when a record is inserted into any one of those tables.
If you provide some more information like:
An example of an insert
The resulting change you would like
to see as a result of that insert
I can try and give you some more details.
UPDATE
Based on your new comments I suspect that you are working with a denormalized database schema. Below is how I would suggest you structure your tables in the Employee-Medical visit scenario you discussed:
Employee
--------
EmployeeId
fName
lName
EmployeeMedicalVisit
--------------------
VisitId
EmployeeId
Date
Cost
Some important things:
Note that I am not entering the
employees name into the
EmployeeMedicalVisit table, just the EmployeeId. This
helps to maintain data integrity and
complies with First Normal Form
You should read up on 1st, 2nd and
3rd normal forms. Database
normalization is a very imporant
subject and it will make your life
easier if you can grasp them.
With the above structure, when an employee visited a medical office you would insert a record into EmployeeMedicalVisit. To select all medical visits for an employee you would use the query below:
SELECT e.fName, e.lName
FROM Employee e
INNER JOIN EmployeeMedicalVisit as emv
ON e.EployeeId = emv.EmployeeId
Hope this helps!
Here is a sample trigger that may show you waht you need to have:
Create trigger mytabletrigger ON mytable
For INSERT
AS
INSERT MYOTHERTABLE (MytableId, insertdate)
select mytableid, getdate() from inserted
In a trigger you have two psuedotables available, inserted and deleted. The inserted table constains the data that is being inserted into the table you have the trigger on including any autogenerated id. That is how you get the data to the other table assuming you don't need other data at the same time. YOu can get other data from system stored procuders or joins to other tables but not from a form in the application.
If you do need other data that isn't available in a trigger (such as other values from a form, then you need to write a sttored procedure to insert to one table and return the id value through an output clause or using scope_identity() and then use that data to build the insert for the next table.

Resources