How do I resolve this issue of sqlite? - database

I'm new to this. I have tried running "run selected Query" for the following command:
-- SQLite
INSERT INTO Users (Id, UserName)
VALUES (1, "Bob");
INSERT INTO Users (Id, UserName)
VALUES (2, "Tom");
INSERT INTO Users (Id, UserName)
VALUES (3, "Jane");
I have received the following error:
[10:55:09 AM][vscode-sqlite][ERROR] UNIQUE constraint failed: Users.Id
[10:55:52 AM][vscode-sqlite][ERROR] UNIQUE constraint failed: Users.Id
I don't know how to continue. Any help would be appreciated.
Thank you

It's quite obvious that there already are rows with those Ids in your database, and Id is an unique key.
There are a couple things you can do, and which is sensible depends on what you're really trying to do (and your database schema). I've tried to order these from more sensible to less sensible.
Use another Id for new rows. If the Id column is set autoincrement, you don't need to pass it at all. INSERT INTO USERS (UserName) VALUES ("Ali"); If it's not, INSERT INTO USERS (Id, UserName) VALUES (4, "Ali"); and so on.
Delete the old rows so you can use the same Ids.
Make the Id column non-unique.

Related

In SQLITE, How do I increase my column value "rayHits" by 1 every time there is an identical row in a table? [duplicate]

I've found a few "would be" solutions for the classic "How do I insert a new record or update one if it already exists" but I cannot get any of them to work in SQLite.
I have a table defined as follows:
CREATE TABLE Book
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name VARCHAR(60) UNIQUE,
TypeID INTEGER,
Level INTEGER,
Seen INTEGER
What I want to do is add a record with a unique Name. If the Name already exists, I want to modify the fields.
Can somebody tell me how to do this please?
Have a look at http://sqlite.org/lang_conflict.html.
You want something like:
insert or replace into Book (ID, Name, TypeID, Level, Seen) values
((select ID from Book where Name = "SearchName"), "SearchName", ...);
Note that any field not in the insert list will be set to NULL if the row already exists in the table. This is why there's a subselect for the ID column: In the replacement case the statement would set it to NULL and then a fresh ID would be allocated.
This approach can also be used if you want to leave particular field values alone if the row in the replacement case but set the field to NULL in the insert case.
For example, assuming you want to leave Seen alone:
insert or replace into Book (ID, Name, TypeID, Level, Seen) values (
(select ID from Book where Name = "SearchName"),
"SearchName",
5,
6,
(select Seen from Book where Name = "SearchName"));
You should use the INSERT OR IGNORE command followed by an UPDATE command:
In the following example name is a primary key:
INSERT OR IGNORE INTO my_table (name, age) VALUES ('Karen', 34)
UPDATE my_table SET age = 34 WHERE name='Karen'
The first command will insert the record. If the record exists, it will ignore the error caused by the conflict with an existing primary key.
The second command will update the record (which now definitely exists)
You need to set a constraint on the table to trigger a "conflict" which you then resolve by doing a replace:
CREATE TABLE data (id INTEGER PRIMARY KEY, event_id INTEGER, track_id INTEGER, value REAL);
CREATE UNIQUE INDEX data_idx ON data(event_id, track_id);
Then you can issue:
INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 2, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 5);
The "SELECT * FROM data" will give you:
2|2|2|3.0
3|1|2|5.0
Note that the data.id is "3" and not "1" because REPLACE does a DELETE and INSERT, not an UPDATE. This also means that you must ensure that you define all necessary columns or you will get unexpected NULL values.
INSERT OR REPLACE will replace the other fields to default value.
sqlite> CREATE TABLE Book (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT,
TypeID INTEGER,
Level INTEGER,
Seen INTEGER
);
sqlite> INSERT INTO Book VALUES (1001, 'C++', 10, 10, 0);
sqlite> SELECT * FROM Book;
1001|C++|10|10|0
sqlite> INSERT OR REPLACE INTO Book(ID, Name) VALUES(1001, 'SQLite');
sqlite> SELECT * FROM Book;
1001|SQLite|||
If you want to preserve the other field
Method 1
sqlite> SELECT * FROM Book;
1001|C++|10|10|0
sqlite> INSERT OR IGNORE INTO Book(ID) VALUES(1001);
sqlite> UPDATE Book SET Name='SQLite' WHERE ID=1001;
sqlite> SELECT * FROM Book;
1001|SQLite|10|10|0
Method 2
Using UPSERT (syntax was added to SQLite with version 3.24.0 (2018-06-04))
INSERT INTO Book (ID, Name)
VALUES (1001, 'SQLite')
ON CONFLICT (ID) DO
UPDATE SET Name=excluded.Name;
The excluded. prefix equal to the value in VALUES ('SQLite').
Firstly update it. If affected row count = 0 then insert it. Its the easiest and suitable for all RDBMS.
Upsert is what you want. UPSERT syntax was added to SQLite with version 3.24.0 (2018-06-04).
CREATE TABLE phonebook2(
name TEXT PRIMARY KEY,
phonenumber TEXT,
validDate DATE
);
INSERT INTO phonebook2(name,phonenumber,validDate)
VALUES('Alice','704-555-1212','2018-05-08')
ON CONFLICT(name) DO UPDATE SET
phonenumber=excluded.phonenumber,
validDate=excluded.validDate
WHERE excluded.validDate>phonebook2.validDate;
Be warned that at this point the actual word "UPSERT" is not part of the upsert syntax.
The correct syntax is
INSERT INTO ... ON CONFLICT(...) DO UPDATE SET...
and if you are doing INSERT INTO SELECT ... your select needs at least WHERE true to solve parser ambiguity about the token ON with the join syntax.
Be warned that INSERT OR REPLACE... will delete the record before inserting a new one if it has to replace, which could be bad if you have foreign key cascades or other delete triggers.
If you have no primary key, You can insert if not exist, then do an update. The table must contain at least one entry before using this.
INSERT INTO Test
(id, name)
SELECT
101 as id,
'Bob' as name
FROM Test
WHERE NOT EXISTS(SELECT * FROM Test WHERE id = 101 and name = 'Bob') LIMIT 1;
Update Test SET id='101' WHERE name='Bob';
I believe you want UPSERT.
"INSERT OR REPLACE" without the additional trickery in that answer will reset any fields you don't specify to NULL or other default value. (This behavior of INSERT OR REPLACE is unlike UPDATE; it's exactly like INSERT, because it actually is INSERT; however if what you wanted is UPDATE-if-exists you probably want the UPDATE semantics and will be unpleasantly surprised by the actual result.)
The trickery from the suggested UPSERT implementation is basically to use INSERT OR REPLACE, but specify all fields, using embedded SELECT clauses to retrieve the current value for fields you don't want to change.
I think it's worth pointing out that there can be some unexpected behaviour here if you don't thoroughly understand how PRIMARY KEY and UNIQUE interact.
As an example, if you want to insert a record only if the NAME field isn't currently taken, and if it is, you want a constraint exception to fire to tell you, then INSERT OR REPLACE will not throw and exception and instead will resolve the UNIQUE constraint itself by replacing the conflicting record (the existing record with the same NAME). Gaspard's demonstrates this really well in his answer above.
If you want a constraint exception to fire, you have to use an INSERT statement, and rely on a separate UPDATE command to update the record once you know the name isn't taken.

Dynamic data masking by using a dynamic row filter in SSAS Tabular

I am trying to implement a way to use Dynamic Data Masking on a SSAS Tabular Import. By default this is not supported on SQL Server Analysis Services 2016 (as far as I know). I think I have found a way to implement this anyway using a Dynamic Row Level Security. However, my results are not as expected.
My case is an Employee table. It contains roughly 2000 rows, my test user is authorized to see about 50.
I have imported the Employee table, added an Security table (EmployeeKey, Username) and set a row filter on the Employee table. More or less in the same way as the sample from Microsoft.
Additionally I have added a table named EmployeeMask which contains the same 2000 rows, with the same EmployeeKeys and the same columns. However, I have 'masked' the values of the remaining columns.
Using an MDX query impersonated as my test user I retrieve 50 employees from my Employee table and 2000 employees from my EmployeeMask table. So far so good. Now comes the part where I thought I was clever. I renamed my Employee table EmployeeAuthorized and added a calculated table Employee as follows:
=UNION(
EmployeeAuthorized;
FILTER(
EmployeeMask;
LOOKUPVALUE(EmployeeAuthorized[EmployeeKey]; EmployeeAuthorized[EmployeeKey]; EmployeeMask[EmployeeKey])
= BLANK()
)
)
However, using a MDX query against my new calculated table Employee I get all 2000 rows unmasked. My guess is that the calculated table gets processed beforehand, whereas I thought the DAX-formula would be execute on request. Is my guess right? Any way to fit my requirement?
Sample data:
CREATE TABLE [dbo].[Employee] (--Renamed this to EmployeeAuthorized
[EmployeeKey] INT NOT NULL,
[EmployeeName] VARCHAR(50) NOT NULL
);
INSERT INTO [dbo].[Employee] VALUES
(1, 'A A'), (2, 'B B'), (3, 'C C');
CREATE TABLE [dbo].[Fact] (
[EmployeeKey] INT NOT NULL,
[Value] INT NOT NULL
);
INSERT INTO [dbo].[Fact] VALUES
(1, 1), (2, 2), (3, 5), (3, 8);
CREATE TABLE [dbo].[Security] (
[EmployeeKey] INT NOT NULL,
[UserName] VARCHAR(50) NOT NULL
);
INSERT INTO [dbo].[Security] VALUES
(1, 'domain\u1'), (2, 'domain\u1'), (3, 'domain\u1'),
(1, 'domain\u2');
And if needed:
CREATE TABLE [dbo].[EmployeeMask] (
[EmployeeKey] INT NOT NULL,
[EmployeeName] VARCHAR(50) NOT NULL
);
INSERT INTO [dbo].[EmployeeMask] VALUES
(1, 'masked'), (2, 'masked'), (3, 'masked');
I'm trying to accomplish the following:
Ditch UNION it ignores filter context and your RLS. Use LOOKUPVALUE to make sure the user has access to the rows on EmployeeMasked based on if their EmployeeKey exists on EmployeeAuthorized
Edit your EmployeeAuthorized table so it contains a ADUsername column. For each EmployeeKey, store their ADUsername value that would be returned from the dax function USERNAME()
Edit the Role you created and go to the Row Filters tab.
Find the EmployeeMask table
Add the following DAX filter so the Role enforces users who belong to the role can only see rows on EmployeeMask if their EmployeeKey/ADUsername has a corresponding lookup authorization records in EmployeeAuthorizedy.
=EmployeeMask[EmployeeKey]
=LOOKUPVALUE(
EmployeeAuthorizedy[EmployeeKey],
EmployeeAuthorized[EmployeeKey], EmployeeMask[EmployeeKey],
EmployeeAuthorized[ADUsername], USERNAME()
)
I was able to solve this puzzle as follows:
I imported the tables into my SSAS Tabular model. I imported table Employee twice, once as Employee and once as EmployeeKey with only the column EmployeeKey.
As you can see the relationships are as follows:
Fact[EmployeeKey] *:1 (<< To Fact) EmployeeKey[EmployeeKey]
Employee[EmployeeKey] *:1 (<< To Both Tables >>) EmployeeKey[EmployeeKey]
Security[EmployeeKey] *:1 (<< To Security) Employee[EmployeeKey]
I have added a single role with Read permissions and the following Row Filters:
Table Employee: =Employee[EmployeeKey]=LOOKUPVALUE(Security[EmployeeKey]; Security[UserName]; USERNAME(); Security[EmployeeKey]; Employee[EmployeeKey])
Table Security: =FALSE()
Resulting in:

How should a IsPrimaryPhone field be modeled in the database?

A contact can have one or more phone numbers. A way is needed to set one of them as the "Primary" phone number.
What is the best way to model that?
The way I usually see it done is to simply add a field called "is_primary" to the phone. Yet for this to work, when that field is set to true for one record, then all other related phone numbers needs to be set to false.
Is there a way to model it through a relation so only one bit of data needs to be updated?
It seems this could be done through a linking table called PrimaryPhone with
ContactId and PhoneId. If the link exists for a ContactId/PhoneId, then it would be used in the UI to show that it was the primary. If the primary changed, it would only be a matter of changing the one record.
Or is some other way this should be done?
Assuming you have two tables (Contacts and PhoneNumbers) it is pretty simple. You have a column in Contacts for PrimaryPhoneNumberID and it contains the ID of the PhoneNumber. This ensures you can never have more than 1 marked as the primary at any one point in time.
I might try mine like:
CREATE TABLE Contact
(ContactID int NOT NULL PRIMARY KEY
,CreateDate datetime
)
GO
CREATE TABLE Phone
(PhoneID int identity (1,1) PRIMARY KEY
,ContactID int not null
,[Key] varchar(20) not null
,[Value] varchar(20) not null
,[Status] varchar(20) not null
)
GO
ALTER TABLE Phone
ADD CONSTRAINT FK_cnst FOREIGN KEY (ContactID)
REFERENCES Contact (ContactID)
GO
ALTER TABLE phone ADD CONSTRAINT UX_Constraint UNIQUE (ContactID, [Status])
GO
INSERT contact SELECT 1, GETDATE()
INSERT INTO phone (ContactID, [Key], Value, Status) VALUES (1, 'Office', '455-1212', 'Alternate')
INSERT INTO phone (ContactID, [Key], Value, Status) VALUES (1, 'Home', '555-1212', 'Alternate2')
INSERT INTO phone (ContactID, [Key], Value, Status) VALUES (1, 'Cell', '555-1000', 'Primary')
INSERT INTO phone (ContactID, [Key], Value, Status) VALUES (1, 'Cell', '555-1001', 'MistressHotline')
GO
SELECT *
FROM Phone
GO
DROP TABLE phone, Contact
And then of course go query it to see if it will work out or not.
Thanks

SQL Server IDENTITY_INSERT Cannot find the object "TableName"

When I run in java netbeans:
executeUpdate("INSERT INTO TableName (id, name) VALUES (1, 'Name1')")
I get the error:
Cannot insert explicit value for identity column in table 'TableName' when IDENTITY_INSERT is set to OFF
If I run:
executeUpdate("SET IDENTITY_INSERT TableName ON;INSERT INTO TableName (id,name) VALUES (1,'Name1');SET IDENTITY_INSERT TableName OFF;")
I get this error:
Cannot find the object "TableName" because it does not exist or you do not have permissions.
Why does this happen and how can I solve this?
It is sufficient to give ALTER rights.
GRANT ALTER TO USER
https://sqlblog.org/2010/12/14/what-permissions-are-required-for-set-identity_insert-on
Just let the IDENTITY property do what it is supposed to an only pass in the name. No need explicitly attempt to pass in an ID unless you are trying to associate specific ID's with names, in which you'd have to keep up with the values you have used and haven't used, and IDENTITY would then be sort of useless. I'd just add a unique constraint on the ID column in this case.
INSERT INTO TableName (name) VALUES ('Name1')

Can a SQL Server 2000 table have no PK, and therefore contain duplicate records?

I have an audit table and instead of defining an identity or ticketed column, I'm considering just pushing in the records of the recorded table (via triggers).
Can a SQL Server 2000 table have no PK, and therefore contain duplicate records?
If yes, does all I have to do consist of CREATING the TABLE without defining any constraint on it?
Yes, this is possible, but not necessarily a good idea. Replication and efficient indexing will be quite difficult without a primary key.
Yes a table without a primary key or Unique Constraint can have rows that are duplicated
for example
CREATE TABLE bla(ID INT)
INSERT bla (ID) VALUES(1)
INSERT bla (ID) VALUES(1)
INSERT bla (ID) VALUES(1)
SELECT * FROM bla
GO
Yes a SQL Server 2000 table can have no primary key and contain duplicate records and yes you can simply Create a table without defining any constraint on it. However I would not suggest this.
Instead, since you are creating an audit table for another table. Lets say for this example you have a Person Table and a Person Audit table that tracks changes in the person Table.
Create your Audit Table like this
CREATE TABLE dbo.PersonAuditID
(
PersonAuditID int NOT NULL IDENTITY (1, 1),
PersonId int NOT NULL,
FirstName nvarchar(50) NOT NULL,
LastName nvarchar(50) NOT NULL,
PersonWhoMadeTheChange nvarchar(100) NOT NULL,
TimeOfChange datetime NOT NULL,
ChangeAction int NOT NULL,
/* any other fields here*/
CONSTRAINT [PK_PersonAudit] PRIMARY KEY NONCLUSTERED
(
[PersonAuditID] ASC
)
) ON [PRIMARY]
This will give you a primary key, and keep records unique to the table. It also provides the ability to track who made the change, when the change was made, and if the change was an insert, update or delete.
Your triggers would look like the following
CREATE TRIGGER Insert_PERSON
ON PERSON
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO PERSONAUDIT
(PersonID,
FirstName,
LastName,
PersonWhoMadeTheChange,
TimeOfChange,
ChangeAction,
... other fields here
SELECT
PersonID,
FirstName,
LastName,
User(),
getDate(),
1,
... other fields here
FROM INSERTED
END
CREATE TRIGGER Update_PERSON
ON PERSON
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO PERSONAUDIT
(PersonID,
FirstName,
LastName,
PersonWhoMadeTheChange,
TimeOfChange,
ChangeAction,
... other fields here
SELECT
PersonID,
FirstName,
LastName,
User(),
getDate(),
2,
... other fields here
FROM INSERTED
END
CREATE TRIGGER Delete_PERSON
ON PERSON
AFTER DELETE
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO PERSONAUDIT
(PersonID,
FirstName,
LastName,
PersonWhoMadeTheChange,
TimeOfChange,
ChangeAction,
... other fields here
SELECT
PersonID,
FirstName,
LastName,
User(),
getDate(),
3,
... other fields here
FROM DELETED
END
SQL Server 2000+, can have tables without PK. And yes, you create them by no using a constraint.
For an audit table, you need to think of what you may be using the audit data for. And even if you are not doing auditing to spefically use to restore records when unfortunate changes were made, they are inevitably used for this. Will it be easier to identify the record you want to restore if you have a surrogate key that prevents you from accidentally restoring 30 other entries when you only want the most recent? Will a key value help you identify the 32,578 records that were deleted in one batch that needs to be restored?
What we do for auditing is have two tables for each table, one stores information about the batch of records changed, including an auto-incrementing id, the user, the application, the datetime, the number of affected records. The child table then used the ID as the fk and stored the details about the old and new values for each record inserted/updated/deleted. This really helps us when a process bug causes many records to be changed by accident.

Resources