SQL Server : query to replace data - sql-server

I need to take all passwords for a live SQL Server database, and replace them with passwords from a backup.
Basic table setup:
Main:
Account_ID Username Password
----------------------------------
1 Blah gy12uid91
2 Blah2 gy12uid92
Backup:
Account_ID Username Password
----------------------------------
1 Blah xxxxxxxx
2 Blah2 xxxxxxxx
I need to take ONLY the passwords from the backup database, and put them in where the username is the same as the live database, so that both would be the same, but only where the usernames are the same.
I was thinking some kind of query like:
UPDATE livedb
FROM backupdb
WHERE username ='name'
SET password ='xxxxxxxx'
WHERE username ='name'
In other words, I have 3600 rows and need to change all the passwords on a massive scale without just copy pasting.

UPDATE l
SET password=b.password
FROM Livedb.schema.table l
INNER JOIN backupdb.schema.table b
ON l.Username=b.Username

Assuming you have your database restored to another location on the same server and the database are called live and restored:
UPDATE liveUsers
SET liveUsers.password = restoredUsers.password
FROM live.users liveUsers
JOIN restored.users restoredUsers
ON liveUsers.Account_ID = restoredUsers.Account_ID
This will replace the password column form restored into live by matching on Account_ID

Related

MariaDB replication is not working when no database is selected

I'm using MariaDB 10.6.8 and have one of master DB and two of slave DBs. Those DBs are set up for replication.
When I excute INSERT or UPDATE query without database selection, replication doesn't seem to work. In other words, master DB's data is changed but slave DB's data is remains intact.
/* no database is selected */
MariaDB [(none)]> show master status \G
*************************** 1. row ***************************
File: maria-bin.000007
Position: 52259873
Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.000 sec)
MariaDB [(none)]> UPDATE some_database.some_tables SET some_datetime_column = now() WHERE primary_key_column = 1;
Query OK, 1 row affected (0.002 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [(none)]> show master status \G
*************************** 1. row ***************************
File: maria-bin.000007
Position: 52260068
Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.000 sec)
/* only change master database's record even though the replication position is changed */
However, after selecting the database, replication work fine.
/* but, after selecting the database */
MariaDB [(none)]> USE some_database;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [some_database]> UPDATE some_tables SET some_datetime_column = now() WHERE primary_key_column = 1;
Query OK, 1 row affected (0.002 sec)
Rows matched: 1 Changed: 1 Warnings: 0
/* then change master and slave database's record */
Can anyone tell me what could be the cause of this situation?
Regardless of the binary log format (MIXED, STATEMENT, ROW) all DML commands will be written to the binary log file as soon the transaction will be committed.
When using ROW format a TABLE_MAP event will be logged first, which contains a unique ID, the database and table name. The ROW_EVENT (Delete/Insert/Update) refers to one or more table id's to identify the tables used.
The STATEMENT format logs a query event, which contains the default database name, timestamp and the SQL statement. If there is no default database, the statement itself will contain the database name.
Binlog dump example for STATEMENT format (I removed the non relevant parts such as timestamp and user variables from output)
without default database
#230210 4:42:41 server id 1 end_log_pos 474 CRC32 0x1fa4fa55 Query thread_id=5 exec_time=0 error_code=0 xid=0
insert into test.t1 values (1),(2)
/*!*/;
# at 474
#230210 4:42:41 server id 1 end_log_pos 505 CRC32 0xfecc5d48 Xid = 28
COMMIT/*!*/;
# at 505
with default database:
#230210 4:44:35 server id 1 end_log_pos 639 CRC32 0xfc862172 Query thread_id=5 exec_time=0 error_code=0 xid=0
use `test`/*!*/;
insert into t1 values (1),(2)
/*!*/;
# at 639
#230210 4:44:35 server id 1 end_log_pos 670 CRC32 0xca70b57f Xid = 56
COMMIT/*!*/;
If a session doesn't use a default database on the source server, it may not be replicated if a binary log filter was specified on the replica, e.g. replicate_do_db, since the replica doesn't parse the statement but checks if the database name applies to the filter.
To avoid inconsistent data on your replicas I would recommend to use ROW format instead.

Check if my database instance on SQL server is encrypted by TDE?

I have a question about SQL server's transparent encryption (TDE). I need to dump a database instance, which will be restored by another DBA remotely by dumped data files. I was asked to make sure the dumped data files has no TDE so DBA can restore it. I checked online, and I found a query to list the encryption status as follows:
SELECT db_name(database_id), encryption_state
FROM sys.dm_database_encryption_keys;
my database instance is not in the result at all. I run another query as follows:
SELECT
db.name,
db.is_encrypted,
dm.encryption_state,
dm.percent_complete,
dm.key_algorithm,
dm.key_length
FROM
sys.databases db
LEFT OUTER JOIN sys.dm_database_encryption_keys dm
ON db.database_id = dm.database_id;
GO
My database instance has value 0 for is_encrypted, and all other values null.
Does it mean my database instance is not encrypted at all?
If your output looks like this...
name | is_encrypted | encryption_state | percent_complete | key_algorithm | ley_length
--------------------------------------------------------------------------------------------
MyDatabase | 0 | NULL | NULL | NULL | NULL
... your database, [MyDatabase], is NOT encrypted. Nor does it have a database encryption key configured.
If, however, any databases have non-NULLs in columns other than [is_encrypted] (e.g. [encryption_state] = 1), those databases are either encrypted, partially encrypted/decrypted or prepped for encryption.
Read up here for detail on encrpytion states:
https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-database-encryption-keys-transact-sql?view=sql-server-ver15

How to insert username in VS2008(report edition)

I'm creating a new report (*.rdl), and there I want to add username who runs the script (insert).
I've tried on VS2008 through "built-in-fields" function which is "User ID", but it didn't work:
CREATE TABLE #Some_Table
(
Plan_date date null,
Plan_customer int null,
creator_id nvarchar(55) null
)
INSERT INTO Some_Table
(
[Plan_date] ,
[Plan_customer],
[creator_id]
)
SELECT
#p_plan_monthly,
#p_plan_clients,
#creator_id ="user id" --from built-in-fields
Expected result is: Column creator_id is filling with value of username from active directory who made insert through my report.
To reiterate my comment, as it's is incredibly important:
"You need to use a different account to access your data #whitefang. The sa account should never be used for something as mundane as a report. In truth it should never be used unless you really need sysadmin privileges, or you're doing something like recovering the server. You should have a service account that can do the respective tasks it needs to. If you can suffer injection through those reports, you're service is like an open book to whomever has access."
Now, onto your problem. I would add a further internal parameter on your report. Change the value of the parameter to have the default value of =User!UserID; this will be the ID of the user running the report (perhaps something like StackOverflow\Larnu).
Then map that report parameter to your dataset parameter #creator_id and change your INSERT statement to:
INSERT INTO Some_Table ([Plan_date],
[Plan_customer],
[creator_id])
VALUES (#p_plan_monthly, #p_plan_clients, #creator_id);
Q: "and there I want to add username who runs the script (insert)"
You can use these functions.
-- database user name
SELECT USER_NAME()
-- login identification name
SELECT SUSER_NAME()

SQL query duplicates, self-join, and calculated field

I'm putting together a report to track latency in a SQL Availability Group. I need to find the difference between two times. I have server1, database1 and time1. I need to compare it to server2, database1, and time2. The data is stored in a table, and new data will be appended to the table. The query I'm trying to create will get these new entries (the field Hardened_time_MS_Diff will be NULL) and I need to get the difference between the times returned for the Primary and Secondary servers. Here's an example of the data:
Server_name Database_name Last_Hardened_Time
Server1 ABC 2015-10-08 10:10:05.180
Server2 ABC 2015-10-08 10:10:05.643
My query to get the Hardened_time_MS_Diff values looks like this:
Select a1.server_name, a1.database_name,
Case when a1.Last_Hardened_Time >= a2.Last_Hardened_Time
then
DATEDIFF (MS, a2.Last_Hardened_Time, a1.Last_Hardened_Time)
Else
DATEDIFF (MS, a1.Last_Hardened_Time, a2.Last_Hardened_Time)
End as Hardened
FROM [database].[dbo].[ag_latency] a1
JOIN ag_latency a2
ON a1.database_name = a2.database_name
AND a1.server_name <> a2.server_name
where a1.Hardened_time_MS_Diff is NULL
Right now it's returning some crazy numbers, and duplicates. The first run it'll work fine. The second run my data will look correct only for the servers whose Last_Hardened_time hasn't changed. If it changed I'll get an absolutely huge number for the second batch like this:
Server_name Database_name Last_Hardened_Time Hardened_time_MS_Diff
Server1 ABC 2015-10-09 12:00:05.013 26
Server2 ABC 2015-10-09 12:00:05.040 26
Server1 ABC 2015-10-09 12:15:07.843 -902803
Server2 ABC 2015-10-09 12:15:07.877 -902863
How can I get this to do what I want it to do?
Also, the part to get the data is in Powershell, so if there's an easier way to manipulate the data table in PoSH and then push that data down let me know.
Thanks in advance!
Simply answer your question, your join clause won't work when you have multiple pair of timestamps - it will join not only the row1-row2 and row3-row4, but also join row1-row4 and row2-row3, which the later two doesn't make sense to your report.
One possible solution would be eliminate any time difference greater than a threshold (say 1000 MilliSec, according to your sample data). So your where clause would look like
where a1.Hardened_time_MS_Diff is NULL AND (DATEDIFF (MS, a2.Last_Hardened_Time, a1.Last_Hardened_Time) < 1000 AND DATEDIFF (MS, a2.Last_Hardened_Time, a1.Last_Hardened_Time) > -1000)
Another solution would be more robust, but requires you to change your table schema. You need to add a column to the table, indicate which 2 rows are paired. For example, assign 1 to first two rows and 2 to last two rows, and then join table a1 and a2 by this column.
Key Server_name Database_name Last_Hardened_Time Hardened_time_MS_Diff
1 Server1 ABC 2015-10-09 12:00:05.013 26
1 Server2 ABC 2015-10-09 12:00:05.040 26
2 Server1 ABC 2015-10-09 12:15:07.843 -902803
2 Server2 ABC 2015-10-09 12:15:07.877 -902863
For the powershell part, can you please elaborate what you need more specifically?
Henry

How to parse data in SQL Server 2008?

I have a column name called Username in my table in SQL Server 2008.
Username has following data
Username
corp\abc
corp\petern
corp\timw
and so on
I need my Username to be
Username
abc
petern
timw
how do I parse the data in Username to skip corp\ ?
Thanks.
You could use PARSENAME to split the data but the function uses dot (.) as the delimiter. So, you have to first replace the backward slashes (\) with period or dot (.).
Click here to view the demo in SQL Fiddle.
Script:
CREATE TABLE users
(
username VARCHAR(30) NOT NULL
);
INSERT INTO users (username) VALUES
('corp\abc'),
('corp\corporate\'),
('corp\yescorp'),
('corp\def'),
('\corpabc\'),
('corpabc\');
SELECT username
, PARSENAME(REPLACE(username, '\', '.'), 1) AS usernameonly
FROM users;
Output:
USERNAME USERNAMEONLY
----------------- ------------
corp\abc abc
corp\corporate\
corp\yescorp yescorp
corp\def def
\corpabc\
corpabc\
You might use following expression to extract username:
select substring (username, charindex ('\', username, 1) + 1, len(username))
If there is no backslash in username function will return entire username - practical if you mix sql server and Windows authentication.
Update dbo.Users
Set Username = replace(Username, 'corp\\', '');
Please check the quoting beforehand, by first checking whether the results of select seem ok (in general it's a good practice with data updating statements):
select replace(Username, 'corp\\', '') from dbo.Users
You can get the username like this:
SELECT RIGHT('corp\username',LEN('corp\username')-PATINDEX('%\%','corp\username'))
=>
SELECT RIGHT(username,LEN(username)-PATINDEX('%\%',username))
This work on text, nvarchar(n - max)

Resources