SQL Server Updating a column in one table with column from another - sql

noob SQL question here. I have a database in SQL Server 2012 and access to another MySQL database with information I'd like to pull.
I would like to update a column representing quantities of a workstation, and that information is present on the other database. I would like to structure a query that updates quantities of all items where model numbers match in each database.
I'll include two select statements to demonstrate what I'd like to work with.
The data from the other database I want to pull from.
SELECT *
FROM OPENQUERY(S3MONITOR,
'SELECT count(BuildDriver) AS ''# of Workstations'', BuildDriver AS ''Workstation Model''
FROM workstation
GROUP BY BuildDriver')
Which produces this result
My database that I'd like to update.
SELECT NumOfDevices, Model
FROM dbo.Currency
INNER JOIN dbo.SubCategory
ON Currency.SubCategoryId = SubCategory.SubCategoryId
WHERE SubCategory.SubCategoryName = 'WorkStation';
Which produces this result
The models will be updated in my database to make sure model names correspond to one another but in the interim I'd like to test a query using the M93z. So what would be the most ideal way of updating NumofDevices in my database using # of Workstations in the other database, where the model names are equal?
Sorry if this is an obvious question, I'm still an SQL noob and it's still not intuitive to me when it comes to these kinds of things.
EDIT: The end goal is to routinely update all Workstation quantities nightly through an SQL Server Agent scheduled job but I'll cross that bridge when I come to it (I actually have some faith that I'll be able to apply the query solution to this job as soon as it's figured out) but I want to include this information in the event that it changes any of your suggestions.

You can use join in the update statement.
with newvals as (
SELECT *
FROM OPENQUERY(S3MONITOR,
'SELECT count(BuildDriver) AS ''# of Workstations'', BuildDriver AS ''Workstation Model''
FROM workstation
GROUP BY BuildDriver'
) oq
)
update c
set NumOfDevices = newvals.num_workstations
from dbo.Currency c join
dbo.SubCategory sc
on c.SubCategoryId = sc.SubCategoryId join
newvals
on newvals.model = c.model
where sc.SubCategoryName = 'WorkStation';
Note: This updates values already in the table. You might want to use merge if you want to add new rows as well. If this is the case, ask another question, because this question is specifically about updating.

Related

Compare two tables on two sql servers

i wanted to compare and identify certain [transaction ids] that exist in one table which is located in server 1 but does not exist in a similar transformed table on a different server (server 2).
These two tables were supposed to be the same but we noticed some transaction ids were missing on the table that is located in server 2. My goal is to identify all the missing transaction ids.
The query that i am looking to write is as below
SELECT
server_1.table_1.[transaction_id] from server_1.table_1
JOIN
server_2.table_2 ON
Table_1.[transaction_id] = Table_2.[transaction_id]
WHERE
server_1.table_1.[transaction_id] NOT IN server_2.table_2.[transaction_id]
one recommendation I have received was
"Let's select the IDs from the source select the result, right click and in SQL complete select general temp table script
Then you can run the scripts on the target server to create a temptable and perform your analysis
Because of the size of the table perhaps you need to do its in batches"
if anyone can help me explain this process as well please?
Thank you very much for your help in advance
i am new for this , i apologize if I have not explained it enough or if i am not clear with my ask
You can do that with a simple OUTER join (LEFT JOIN):
SELECT table1.transaction_id as missing_in_table2
FROM table1 LEFT JOIN table2
ON table1.transaction_id=table2.transaction_id
WHERE table2.transaction_id IS NULL

SSRS - Display fields based on criteria from two different datasets

I'm working on a SSRS report where I am pulling claim data from two different datasets (creatively named DataSet1 and DataSet2) and it is creating two separate tables and information here:
You'll see the fields pretty easily spelled out, what I am looking to do is create another table with data that displays ONLY data that is not matching in both, so in the example given, it would display the claim no, trans date, and amount of everything other than CLAIM987654321 (which is the only unique identifier, as with the way things are processed the dates may be different.)
I know how to display only based on a query, but am unsure how to make the multi-dataset comparison happen.
Sadly there is no possible way to have the data combine to my knowledge, there may be, but I am unsure how to do this. Below are the queries I am using within SSMS.
The servers are already linked per previous joins, but if there is a way to manipulate the data into a single pull, I am unfamiliar with that.
NEW UPDATE: I threw together a really ugly linked server pull, but it is only pulling the data that exists in both, and I would want the data that is NOT as well.
You'll need to use FULL JOIN
So if you want to see only data that does not appear in both tables then I would do something like this. (I've not used you full qualifiers for clarity but you'll get the idea)
SELECT
COALESCE(c.ClaimNo, r.CHK_claim_number) AS [Claim Number] -- COALESCE will get first non null value
, COALESCE(d.OtherPayer1Paid, r.CHK_payable_cost) AS [Amount]
, COALESCE(c.TransactionDate, d.CHK_paid_date) AS [Transaction Date]
FROM EDI_Claims c -- Full join shows all records, null will show for missing records
JOIN EDI_ClaimDetails d ON c.id =d.claimid
FULL JOIN PaidClaims_by_CheckRun r ON r.CHK_claim_number = c.claimno
WHERE d.OtherPayer1Paid != 0
AND (r.CHK_ClaimNUmber IS NULL OR c.ClaimNo IS NULL) -- only show when one side of the join fails
ORDER BY c.TrandactionDate

MS Access - Log daily totals of query in new table

I have an ODBC database that I've linked to an Access table. I've been using Access to generate some custom queries/reports.
However, this ODBC database changes frequently and I'm trying to discover where the discrepancy is coming from. (hundreds of thousands of records to go through, but I can easily filter it down into what I'm concerned about)
Right now I've been manually pulling the data each day, exporting to Excel, counting the totals for each category I want to track, and logging in another Excel file.
I'd rather automate this in Access if possible, but haven't been able to get my heard around it yet.
I've already linked the ODBC databases I'm concerned with, and can generate the query I want to generate.
What I'm struggling with is how to capture this daily and then log that total so I can trend it over a given time period.
If it the data was constant, this would be easy for me to understand/do. However, the data can change daily.
EX: This is a database of work orders. Work orders(which are basically my primary key) are assigned to different departments. A single work order can belong to many different departments and have multiple tasks/holds/actions tied to it.
Work Order 0237153-03 could be assigned to Department A today, but then could be reassigned to Department B tomorrow.
These work orders also have "ranking codes" such as Priority A, B, C. These too can be changed at any given time. Today Work Order 0237153-03 could be priority A, but tomorrow someone may decide that it should actually be Priority B.
This is why I want to capture all available data each day (The new work orders that have come in overnight, and all the old work orders that may have had changes made to them), count the totals of the different fields I'm concerned about, then log this data.
Then repeat this everyday.
the question you ask is very vague so here is a general answer.
You are counting the items you get from a database table.
It may be that you don't need to actually count them every day, but if the table in the database stores all the data for every day, you simply need to create a query to count the items that are in the table for every day that is stored in the table.
You are right that this would be best done in access.
You might not have the "log the counts in another table" though.
It seems you are quite new to access so you might benefit form these links videos numbered 61, 70 here and also video 7 here
These will help or buy a book / use web resources.
PART2.
If you have to bodge it because you can't get the ODBC database to use triggers/data macros to log a history you could store a history yourself like this.... BUT you have to do it EVERY day.
0 On day 1 take a full copy of the ODBC data as YOURTABLE. Add a field "dump Number" and set it all to 1.
1. Link to the ODBC data every day.
join from YOURTABLE to the ODBC table and find any records that have changed (ie test just the fields you want to monitor and if any of them have changed...).
Append these changed records to YOURTABLE with a new value for "dump number of 2" This MUST always increment!
You can now write SQL to get the most recent record for each primary key.
SELECT *
FROM Mytable
WHERE
(
SELECT PrimaryKeyFields, MAX(DumpNumber) AS MAXDumpNumber
FROM Mytable
GROUP BY PrimaryKeyFields
) AS T1
ON t1.PrimaryKeyFields = Mytable.PrimaryKeyFields
AND t1.MAXDumpNumber= Mytable.DumpNumber
You can compare the most recent records with any previous records.
ie to get the previous dump
Note that this will NOT work in the abvoe SQL (unless you always keep every record!)
AND t1.MAXDumpNumber-1 = Mytable.DumpNumber
Use something like this to get the previous row:
SELECT *
FROM Mytable
INNER JOIN
(
SELECT PrimaryKeyFields
, MAX(DumpNumber) AS MAXDumpNumber
FROM Mytable
INNER JOIN
(
SELECT PrimaryKeyFields
, MAX(DumpNumber) AS MAXDumpNumber
FROM Mytable
GROUP BY PrimaryKeyFields
) AS TabLatest
ON TabLatest.PrimaryKeyFields = Mytable.PrimaryKeyFields
AND
TabLatest.MAXDumpNumber <> Mytable.DumpNumber
-- Note that the <> is VERY important
GROUP BY PrimaryKeyFields
) AS T1
ON t1.PrimaryKeyFields = Mytable.PrimaryKeyFields
AND t1.MAXDumpNumber= Mytable.DumpNumber
Create 4 and 5 and MS Access named queries (or SS views) and then treate them like tables to do comparison.
Make sure you have indexes created on the PK fields and the DumpNumber and they shoudl be unique - this will speed things up....
Finish it in time for christmas... and flag this as an answer!

Selecting from multiple tables in VBScript/ASP

I understand that this question is based on a very old programming language, and is also based on some poor practices with database design, but I am hoping for some guidance as my VBScript is not up to scratch, and at my job I am unable to change my database structure or my scripting language.
I am working on a webpage that gets its data from a database which originally contained all of its data in one table. However, the database managers at my work have decided to split the large table into many smaller ones. Our webpage contains an online map with point data, which displays in a new page a table of data for each point found. The code to connect to the database originally looked something like this:
sql_select = "SELECT * FROM table_name WHERE master_id='"&key&"'"
Set rs = Conn.Execute(sql_select)
This code worked fine for what it was used for. However, now that the main table has been divided into seven sub-tables, I am in need of a code that will select all data from all tables, and then filter them based on their master id.
I feel like I understand the theory of how to make this work (I am not a computer science major, so this is still somewhat foreign to me), and that I need to implement a union. My main problem is dealing with the syntax of VBScript/ASP in creating this script, as it seems like everything I try doesn't work.
Can anybody please lend me some guidance? Much appreciated!
It sounds like what you actually need is a JOIN rather than a UNION. A JOIN glues together data from several places into a single row, while a UNION glues together several rows of data in a collection of more rows:
The DB Query
In this case you have a master table and several sub tables. For the example's sake I'll assume the tables look like:
Table Columns
---------------------------
MasterTable MasterId, M1, M2, M3
SubTableA SubTableAId, MasterId, A1, A2, A3
SubTableB SubTableBId, MasterId, B1, B2, B3
So if you were wanting to retrieve the columns M1-3 and A1-A3 then you could join the columns from MasterTable with the columns on SubTableA where they have matching MasterId values:
SELECT *
FROM MasterTable MT
INNER JOIN SubTableA STA ON MT.MasterId = STA.MasterId
The MT and the STA are aliases so we can don't have to type out the entire tables names when we're clarifying which of the two master id's we're referring to.
If we then only wanted the values for a single, specific master ID we could add that as a where clause on the end:
SELECT *
FROM MasterTable MT
INNER JOIN SubTableA STA ON MT.MasterId = STA.MasterId
WHERE MT.MasterId = ?
If we needed columns from additional tables, we could JOIN to those tables as well:
SELECT *
FROM MasterTable MT
INNER JOIN SubTableA STA ON MT.MasterId = STA.MasterId
INNER JOIN SubTableB STB ON MT.MasterId = STB.MasterId
WHERE MT.MasterId = ?
We are specifying an INNER JOIN because we only want records returned where there are matching values in all three tables. If SubTableB only had values for each master id some of the time, then we would want to switch to a LEFT JOIN or LEFT OUTER JOIN which would tell the database to return our columns from the LEFT side of the join even when there aren't matching columns available on the right side.
So to get all columns in a situation where we may not always have SubTableB records but still want the Master and SubTableA columns:
SELECT *
FROM MasterTable MT
INNER JOIN SubTableA STA ON MT.MasterId = STA.MasterId
LEFT JOIN SubTableB STB ON MT.MasterId = STB.MasterId
WHERE MT.MasterId = ?
if it is possible that you will have multiple records in one of the SubTables for a single MasterId then the rows will be returned with each possible combinations of the table rows that match the JOIN criteria.
So if we had one record in the MasterTable with an ID of 5, 1 in SubTableA with a master id of 5, and 3 in SubTableB with an id of 5, then we would actually receive 3 rows back, 1 for each combination of MasterTable and SubTableA values with the SubTable3 values. So in your client-side you will either need to be able to handle the duplicate values/rows or you split the query to execute the query from SubTableB separately.
VBScript SQL Code
The code you provided, while a sample, has two downsides. One, because you are concatenating the argument into the database string, special characters in that string could break your SQL statement or, if you are retrieving that value from a form POST, Querystring, etc, then an end user could actually inject a SQL statement into the variable to run on your database (potentially dropping valuable records, manipulating the database, or potentially even uploading trojans or executables to the server, depending on the permissions level).
The second downside is that there are potential downsides to executing a string like that. Depending on your database engine you could take minor performance hits from implicit type conversions, lack of plan caching, etc simply because the statement was delivered as a non-parametrized string.
To resolve these issues, you should look into using parametrized SQL statements or creating a stored procedure for your statement and calling that with parametrized values. the ADODB object has support for parameters:
Dim yourKeyValue : yourKeyValue = 5
Dim objConn, objCommand, rsResults
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open("Your connection string")
Set objCommand = Server.CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConn
objCommand.CommandText = "YourStoreProcName"
objCommand.CommandType = 4 'stored proc type/enum
objCommand.Parameters.Append objCommand.CreateParameter("Key", 3,1,,yourKeyValue)
set rsResults = objCommand.Execute()
More information on parameters and constants: http://www.w3schools.com/ado/met_comm_createparameter.asp
More info on CommandType: http://www.w3schools.com/ado/prop_comm_commandtype.asp
You could change out the command text for a SQL string instead of a stored procedure and use ?-marks as placeholders for the parameters you define.
More Cleanup
Just a little more cleanup real quick.
Rather than specifying a * for your query, you will probably want to specify the list of columns you actually want returned. This will reduce the amount of data coming across the wire to only what you need, tell the database exactly what you need so it doesn't have to pre-lookup the fieldnames on it's own, and it will reduce some of the confusion in your recordset object (you would otherwise have quite a few master id columns, for instance).
As Dee mentioned in their response, you probably should include whoever made the database changes, but I don't think you want to just dump this in their laps because you will want to understand why and how it works, otherwise trying to make additional changes or maintaining the app will be that much harder than it already is.
The database managers split the table up, tell them you need a new SQL statement to replace the one you have. Since they know the new structure, they can write it for you in a couple of minutes.

Reconciling a column across two tables in SQL Server

There are two Databases, Database A has a table A with columns of id, group and flag. Database B has a table B with columns of ID and flag. Table B is essentially a subset of table A where the group == 'B'.
They are updated/created in odd ways that are outside my understanding at this time, and are beyond the scope of this question (this is not the time to fix the basic setup and practices of this client).
The problem is that when the flag in Table A is updated, it is not reflected in table B, but should be. This is not a time-critical problem, so it was suggested I create a job to handle this. Maybe because it's the end of the week, or maybe because I've never written more than the most basic stored procedure (I'm a programmer, not a DBA), but I'm not sure how to go about this.
At a simplistic level, the stored procedure would be something along of the lines of
Select * in table A where group == B
Then, loop through the resultset, and for each id, update the flag.
But I'm not even sure how to loop in a stored procedure like this. Suggestions? Example code would be preferred.
Complication: Alright, this gets a little harder too. For every group, Table B is in a separate database, and we need to update this flag for all groups. So, we would have to set up a separate trigger for each group to handle each DB name.
And yes, inserts to Table B are already handled - this is just to update flag status.
Assuming that ID is a unique key, and that you can use linked servers or some such to run a query across servers, this SQL statement should work (it works for two tables on the same server).
UPDATE Table_B
SET Table_B.Flag = Table_A.Flag
FROM Table_A inner join Table_B on Table_A.id = Table_B.id
(since Table_B already contains the subset of rows from Table_A where group = B, we don't have to include this condition in our query)
If you can't use linked servers, then I might try to do it with some sort of SSIS package. Or I'd use the method described in the linked question (comments, above) to get the relevant data from Database A into a temp table etc. in Database B, and then run this query using the temp table.
UPDATE
DatabaseB.dbo.Table_B
SET
DatabaseB.dbo.Table_B.[Flag] = DatabaseA.dbo.Table_A.Flag
FROM
DatabaseA.dbo.Table_A inner join DatabaseB.dbo.Table_B B
on DatabaseA.dbo.id = DatabaseB.dbo.B.id
Complication:
For sevaral groups run one such update SQL per group.
Note you can use Flag without []. I'm using the brackets only because of syntax coloring on stackoverflow.
Create an update trigger on table A that pushes the necessary changes to B as A is modified.
Basically (syntax may not be correct, I can't check it right now). I seem to recall that the inserted table contains all of the updated rows on an update, but you may want to check this to make sure. I think the trigger is the way to go, though.
create trigger update_b_trigger
on Table_A
for update
as
begin
update Table_B
set Table_B.flag = inserted.flag
from inserted
inner join Table_B
on inserted.id = Table_B.id
and inserted.group = 'B'
and inserted.flag <> Table_B.flag
end
[EDIT] I'm assuming that inserts/deletes to Table B are already handled and it's just flag updates to Table B that need to be addressed.