I have a table that has a bunch of different servers most of them are listed as servername.ad.edu. I want to remove everything after the first dot. so it just shows as servername in my table. The code I was provided for the population of the table was not written by me but I did add the LEFT statement to see if I could remove it during population. Here is my code...
DELETE FROM clean_tanium_server;
MERGE clean_tanium_server AS Target
USING tanium_server AS Source
ON Source.computer_id = Target.computer_id AND Source.[ci_installed_application name] = Target.application_name
WHEN NOT MATCHED BY Target THEN
INSERT (computer_id, computer_name, operating_system, application_name, application_normalized_name, chassis_type, cpu_core, cpu_processor, ip_address)
VALUES (Source.computer_id, Source.computer_name, Source.operating_system, Source.[ci_installed_application name], Source.[ci_installed_application normalized_name], Source.chassis_type, Source.cpu_core, Source.cpu_processor, Source.ip_address)
WHEN MATCHED THEN UPDATE SET
*Target.computer_name = LEFT(Source.computer_name, CHARINDEX('.', Source.computer_name) - 1),*
Target.operating_system = Source.operating_system,
Target.application_normalized_name = Source.[ci_installed_application normalized_name]
WHEN NOT MATCHED BY Source THEN
DELETE;
So I can't figure out why when I populate the tables they aren't omitting the .ad.edu portion. Any help is greatly appreciated. Thank you.
How it looks currently:
computer_name
servername1.ad.edu
servername2.ad.edu
servername3.us.edu
How I want it to look:
computer_name
servername1
servername2
servername3
You're only applying the LEFT changes when entering the WHEN MATCHED THEN UPDATE SET block, but as pointed out in the comments, you're emptying the table first, so you'll never match and will only execute the WHEN NOT MATCHED BY Target THEN block which doesn't have your LEFT modifications
Here is a summary of the other answers and comments.
You don't need a MERGE statement because you delete all the rows from the table first - so you just need an INSERT
I would recommend using TRUNCATE rather than DELETE for deleting all rows - unless you have a specific need for it. Pros and Cons of Truncate over Delete
With your INSERT statement use the code that Aaron Bertrand provided to strip the end off your computer name.
TRUNCATE TABLE clean_tanium_server;
INSERT INTO clean_tanium_server (
computer_id
, computer_name
, operating_system
, application_name
, application_normalized_name
, chassis_type
, cpu_core, cpu_processor
, ip_address)
SELECT
computer_id
, LEFT(computer_name, CHARINDEX('.', computer_name + '.') - 1)
, operating_system
, [ci_installed_application name]
, [ci_installed_application normalized_name]
, chassis_type
, cpu_core
, cpu_processor
, ip_address
FROM tanium_server;
Related
I've predominantly used mySQL so moving over to azure and sql server I realise that on duplicate does not work.
I'm trying to do this:
INSERT INTO records (jid, pair, interval, entry) VALUES (1, 'alpha', 3, 'unlimited') ON DUPLICATE KEY UPDATE entry = "limited";
But of course on duplicate key isn't allowed here. So MERGE is the right form.
I've looked at:
https://technet.microsoft.com/en-gb/library/bb522522(v=sql.105).aspx
But honestly the example is a bit excessive and eye watering. Could someone dumb it down for me to fit my example so I can understand it better?
In order to do the merge you need some form of source table/table var for the merge statement. Then you can do the merging. So something along the lines of this maybe (note: not completely syntax checked, apologies in advance):
WITH src AS (
-- This should be your source
SELECT 1 AS Id, 2 AS Val
)
-- The above is not neccessary if you have a source table
MERGE Target -- the detination table, so in your case records
USING src -- as defined above
ON (Target.Id = src.Id) -- how do we join the tables
WHEN NOT MATCHED BY TARGET
-- if we dont match, what do to the destination table. This case insert it.
THEN INSERT(Id, Val) VALUES(src.Id, src.Val)
WHEN MATCHED
-- what do we do if we match. This case update Val
THEN UPDATE SET Target.Val = src.Val;
Don't forget to read the proper syntax page: https://msdn.microsoft.com/en-us/library/bb510625.aspx
I think this translates to your example (tm):
WITH src AS (
-- This should be your source
SELECT 1 AS jid, 'alpha' AS pair, 3 as 'interval'
)
MERGE records -- the detination table, so in your case records
USING src -- as defined above
ON (records.Id = src.Id) -- how do we join the tables
WHEN NOT MATCHED BY TARGET
-- if we dont match, what do to the destination table. This case insert it.
THEN INSERT(jid, pair, interval, entry) VALUES(src.jid, src.pair, src.interval, 'unlimited')
WHEN MATCHED
-- what do we do if we match. This case update Val
THEN UPDATE SET records.entry = 'limited';
I have a table with columns businessname, sortcode and accountnumber all populated, name, nationality and DOB all currently unpopulated. I need to create a trigger to shoot every update to an audit table when any of the null fields are updated so if I change just the name I'll get a timestamp, userid, the field changed, the old value and the new value.. If I changed all 3 null fields I'd like to send 3 rows to the audit table.
Can someone give me a pointer on the logic of this please?
In a very rudimentary format for testing I've got
CREATE TRIGGER RM_UPDATE_TRIGGER ON RM_BASE
ON UPDATE
AS
INSERT INTO RM_AUDITLOG
SELECT CURRENT_TIMESTAMP, SRT_CD
FROM RM_BASE
but this is sending all the current rows across after an UPDATE to any of them, I only want the row that has been affected. I'm not sure if I should be building more tables to join together to get the final answer or using the INSERT/DELETE tables.. I've seen an audit table in this format in previous roles so I know it works but can't figure it out!
Thanks
Yes, you need to use the INSERTED and/or DELETED pseudo-tables as those contain only the rows that have been modified. As in:
CREATE TRIGGER RM_UPDATE_TRIGGER ON RM_BASE
ON UPDATE
AS
INSERT INTO RM_AUDITLOG
SELECT CURRENT_TIMESTAMP, SRT_CD
FROM INSERTED
The INSERTED table has the "new" or "current" version of each row while the DELETED table has the "old" version that has been replaced via the UPDATE operation. This is the case for all versions of SQL Server, at least going back as far as SQL Server 2000.
In order to track the change itself (both "old" and "new" values), then you need to JOIN those two pseudo-tables, as in:
INSERT INTO RM_AUDITLOG
SELECT CURRENT_TIMESTAMP, ins.SRT_CD AS [SRT_CD_new], del.SRT_CD AS [SRT_CD_old]
FROM INSERTED ins
INNER JOIN DELETED del
ON del.PKfield = ins.PKfield
This is the basic operation for capturing changes (unless, of course, you use Change Data Capture) in a DML trigger.
If you want to unpivot this data such that each set of "old" and "new" columns becomes a row, that should be easily adaptable from the above. In that case, you could also add WHERE ISNULL(ins.column, '~~~~') <> ISNULL(del.column, '~~~~') COLLATE Latin1_General_BIN to avoid capturing fields that have not changed. The COLLATE ensures case-sensitive / accent-sensitive / etc comparisons.
Of course, unpivoting makes it really hard to reconstruct the entire row as you are then required to keep the full history forever. You would need to start with the base values for all fields and apply the changes incrementally. The typical audit scenario is to just to capture the row that has fields for both old and new for each source field (like I have already shown). If your audit table looks more like:
PKfield, DateModified, businessname_old, businessname_new, sortcode_old, sortcode_new
then you can write a query to identify which fields actually changed by comparing each set (given that more than 1 field can change in the same UPDATE operation), something like:
SELECT PKfield,
DateModified,
CASE
WHEN ISNULL(businessname_old, '~~~~') <> ISNULL(businessname_new, '~~~~')
COLLATE Latin1_General_BIN THEN 'BusinessName ' ELSE ''
END +
CASE
WHEN ISNULL(sortcode_old, '~~~~') <> ISNULL(sortcode_new, '~~~~')
COLLATE Latin1_General_BIN THEN 'SortCode ' ELSE ''
END AS [FieldsChanged]
FROM AuditTable
ORDER BY DateModified DESC;
BUT, if you really want to unpivot the data to have one row per actual changed field, then the following structure should work:
;WITH ins AS
(
SELECT PKfield, FieldName, Value
FROM (
SELECT PKfield, businessname, sortcode, accountnumber, name,
nationality, DOB
FROM INSERTED
) cols
UNPIVOT (Value FOR FieldName IN
(businessname, sortcode, accountnumber, name, nationality, DOB)
) colvals
), del AS
(
SELECT PKfield, FieldName, Value
FROM (
SELECT PKfield, businessname, sortcode, accountnumber, name,
nationality, DOB
FROM DELETED
) cols
UNPIVOT (Value FOR FieldName IN
(businessname, sortcode, accountnumber, name, nationality, DOB)
) colvals
)
INSERT INTO AuditTable (PKfield, DateModified, FieldName, OldValue, NewValue)
SELECT ins.PKfield, CURRENT_TIMESTAMP, ins.FieldName, del.Value, ins.Value
FROM ins
INNER JOIN del
ON del.PKfield = ins.PKfield
AND del.FieldName = ins.FieldName
WHERE ISNULL(del.Value, '~~~~') <>
ISNULL(ins.Value, '~~~~') COLLATE Latin1_General_BIN;
You might need to add a CONVERT(VARCHAR(1000), field) to the WHERE condition if DOB is a DATE or DATETIME field, or if SRT_CD is an INT or other type of number field:
WHERE ISNULL(CONVERT(VARCHAR(1000), del.Value), '~~~~') <>
ISNULL(CONVERT(VARCHAR(1000), ins.Value), '~~~~')
COLLATE Latin1_General_BIN;
I can't figure out even after reading other questions that have a similar title, why this isn't working. I get an error on the final INSERT statement.
WITH qryRecordsNotYetCompleted AS
(
SELECT FormNbr,
UserAssigned,
DateAssignedToAnalyst,
AssignmentStatus,
DateImportedFromSQL,
DateCompletedbyBAA,
DateSentToClaimsToolbar
FROM PENDS_BAA_MASTER WHERE ISNULL(DateCompletedbyBAA,'')=''
)
--/**********************************************************************************************
--2) For all those records, save any ASSIGNMENT information AND original DateImportedFromSQL value
SELECT qryRecordsNotYetCompleted.* INTO #TempPends FROM qryRecordsNotYetCompleted
--/**********************************************************************************************
--2b:
INSERT PENDS_BAA_MASTER_Temp
SELECT * FROM #TempPends
I checked, and PENDS_BAA_MASTER_Temp definitely has columns UserAssigned, DateAssignedToAnalyst, AssignmentStatus, DateImportedFromSQL, DateCompletedByBAA, DateSentToClaimsToolbar. And they are the exact same column types as PENDS_BAA_MASTER, which, due to the flow of my statements, should carry through.
I would do this as a single insert statement. Like this. You have FormNbr in your original query but didn't mention it in the target table.
INSERT PENDS_BAA_MASTER_Temp
(
UserAssigned
, DateAssignedToAnalyst
, AssignmentStatus
, DateImportedFromSQL
, DateCompletedbyBAA
, DateSentToClaimsToolbar
)
SELECT UserAssigned
, DateAssignedToAnalyst
, AssignmentStatus
, DateImportedFromSQL
, DateCompletedbyBAA
, DateSentToClaimsToolbar
FROM PENDS_BAA_MASTER
I've tried searching for this particular topic here, but haven't found the answer... Anyway, my aim is to update table (let's call it t_item), specifically column owner_id with values depending on another table (t_item_geo which is in turn linked to t_geo).
I'm not entirely sure whether the syntax below is actually valid for update statements.
UPDATE t_item SET owner_id= 6993 WHERE t_item.owner_id in
(SELECT t_item.owner_id FROM
t_item,
t_item_geo,
t_geo
WHERE
t_item.id = t_item_geo.item_id and
t_item_geo.geo_id = t_geo.id and
t_item.owner_id in (SELECT id FROM t_user WHERE network_id='fffffff') and
t_geo.id in (SELECT id FROM t_geo WHERE full_name = 'yyyyyyy')
);
Anyway, my problem with this query is that it updates far more rows than it should - if I separate just the select statement Oracle returns ~750 rows but the udpate itself updates more than 4000 rows. It's almost as if the condition was completely ignored - which would point me to perhaps incorrect syntax.
I need to update specific value in the table based on the select from few other 'joined' tables. Hope it makes sense.
Thanks for any contribution!
UPDATE: sorry - maybe it wasn't clear from the question itself, but the correct number of edited items should be ~750 and not ~4000. Thanks!
try this
MERGE INTO t_item
USING
(
SELECT t_item.owner_id FROM
t_item,
t_item_geo,
t_geo,
t_item.rowid rowid_sub
WHERE
t_item.id = t_item_geo.item_id and
t_item_geo.geo_id = t_geo.id and
t_item.owner_id in (SELECT id FROM t_user WHERE network_id='fffffff') and
t_geo.id in (SELECT id FROM t_geo WHERE full_name = 'yyyyyyy')
) on (rowid = rowid_sub)
WHEN MATCHED THEN
UPDATE SET owner_id= 6993;
I'm using parts of a replication script written by a well known blogger. I want to make the part I listed below add 1 more column from a totally different table that only holds 1 row. Basically that table with a single row has a site name on it, and I want that site name from that table to populate as part of this INSERT INTO.
I know SQL 2005 introduced OUTER APPLY, but I am not sure if that is the best method to go with. Any sugegstions are welcome. Thanks.
Insert Into dbo.dba_replicationMonitor
(
monitorDate
, publicationName
, publicationDB
, iteration
, tracer_id
, distributor_latency
, subscriber
, subscriber_db
, subscriber_latency
, overall_latency
, SiteNameFromSiteInfoTable --Need to add this
)
Select
#currentDateTime
, #publicationToTest
, #publicationDB
, iteration
, tracer_id
, IsNull(distributor_latency, 0)
, subscriber
, subscriber_db
, IsNull(subscriber_latency, 0)
, IsNull(overall_latency,
IsNull(distributor_latency, 0) + IsNull(subscriber_latency, 0
)
, sitename = 'SELECT sitename FROM tblSiteInfo' --need this query to insert as well
)
From #tokenResults;
I was thinking of a variable but I don't thnk passing the variable will be enough. Any help is greatly appreciated. Thanks.
You can just join to the second table as normal. If there's only one row in this other table (and will only ever be one row), it's not going to double your results. So, like this:
INSERT INTO dbo.dba_replicationMonitor (_column_list_)
SELECT _#ToeknResultsColumns_, b.sitename
FROM #TokenResults as a
JOIN tblSiteInfo as b
ON 1 = 1