Duplicate multiple records with one INSERT statement - sql

In MS-Access 2019, I'd like to duplicate existing records from tblTest and change one field tLink as a foreign key to another table.
I know how to do it with VBA looping over recordsets, but I'd like to use SQL here.
I assume it can be solved with a single statement, and as SQL-newbie I'm eager to learn how to do it.
So let's assume a simple table tblTest, tID is Primary Key and auto-number
tID tLink tName
Long Long Text(50)
-----------------------------
1 3 Bill
2 17 Sue
3 9 Tom
4 3 Chris
I'd like to duplicate all records with tLink = 3 and set their tLink to 1.
When snooping around in various tutorials, I learned ...
INSERT INTO tblTest SELECT * FROM tblTest WHERE tID=1
... but this fails because of tID having to be a unique value.
So I am stuck at this point, and removing the primary key from the table is not an option here. Is there a way around it?
So, (1) how to duplicate one record without running into the primary key issue, and then, (2) multiple records with 1 SQL statement?
I would then use UPDATE to set tLink to 1 WHERE tLink=3

I'd like to duplicate all records with tLink = 3 and set their tLink to 1.
If you have an auto-number column, then you can just leave it apart in the insert statement. Access will automatically assign a new value for every inserted row.
What you want should be as simple as:
INSERT INTO tblTest(tLink, tName) SELECT 1, tName FROM tblTest WHERE tLink = 3

Related

Database cache in SQL Or correcting autoincrement [duplicate]

This question already has answers here:
How to get rid of gaps in rowid numbering after deleting rows?
(4 answers)
Closed 5 months ago.
I've created 2 rows in an table in SQL (sqlite3 on cmd) and then deleted 1 of them.
CREATE TABLE sample1( name TEXT, id INTEGER PRIMARY KEY AUTOINCREMENT);
INSERT INTO sample1 VALUES ('ROY',1);
INSERT INTO sample1(name) VALUES ('RAJ');
DELETE FROM sample1 WHERE id = 2;
Later when I inserted another row, its id was given 3 by the system instead of 2.
INSERT INTO sample1 VALUES ('AMIE',NULL);
SELECT * FROM sample1;
picture of table
How do I correct it so the next values are given right id's automatically? Or how do I clear the sql database cache to solve it?
The simplest fix to resolve the problem you describe, is to omit AUTOINCREMENT.
The result of your test would then be as you wish.
However, the rowid (which the id column is an alias of, if INTEGER PRIMARY KEY is specified, with or without AUTOINCREMENT), will still be generated and probably be 1 higher than the highest existing id (alias of rowid).
There is a subtle difference between using and not using AUTOINCREMENT.
without AUTOINCREMENT then the generated value of the rowid and therefore it's alias will be the highest existing rowid for the table plus 1 (not absolutely guaranteed though).
with AUTOINCREMENT the generated value will be 1 plus the higher of:-
the highest existing rowid, or
the highest used rowid
the highest, in some circumstances, may have only existed briefly
In your example as 2 had been used then 2 + 1 = 3 even though 2 had been deleted.
Using AUTOINCREMENT is inefficient as to know what the last used value was requires a system table, sqlite_sequence and it being accessed to store the latest id and also to retrieve the id.
The SQLite AUTOINCREMENT documentation, says this:-
The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and should be avoided if not strictly needed. It is usually not needed.
There are other differences, such as with AUTOINCREMENT if the id 9223372036854775807 has been reached, then another insert will result in an SQLITE_FULL error. Whilst without AUTOINCREMENT then an unused id (there would be one as current day storage devices could not hold that number of rows).
The intention of id's (rowid's) is to uniquely identify a row and to be able to access such a row efficiently if accessing it by the id. The intention is not for it to be used as a sequence/order. Using it as a sequence/order number will probably invariably result in unanticipated sequences or inefficient overheads trying to maintain such a sequence/order.
You should always consider that rows are unordered unless specifically ordered by a clause that orders the output, such as an ORDER BY clause.
However, if you take your example a little further, omitting AUTOINCREMENT, will still probably result in the order/sequence issues as if, for example, the row with an id of 1 were deleted instead of 2 then you would end up with id's of 2 and 3.
Perhaps consider the following which shows a) how the limited issue you have posed, is solved without AUTOINCREMENT, and b) that it is not the solution if it is not the highest id that is deleted:-
DROP TABLE IF EXISTS sample1;
CREATE TABLE IF NOT EXISTS sample1( name TEXT, id INTEGER PRIMARY KEY);
INSERT INTO sample1 VALUES ('ROY',1);
INSERT INTO sample1(name) VALUES ('RAJ');
DELETE FROM sample1 WHERE id = 2;
INSERT INTO sample1 VALUES ('AMIE',NULL);
/* Result 1 */
SELECT * FROM sample1;
/* BUT if a lower than the highest id is deleted */
DELETE FROM sample1 WHERE id=1;
INSERT INTO sample1 VALUES ('EMMA',NULL);
/* Result 2 */
SELECT * FROM sample1;
Result 1 (your exact issue resolved)
Result 2 (if not the highest id deleted)

Oracle Enforce Uniqueness

I need to enforce uniqueness on specific data in a table (~10 million rows). This example data illustrates the rule -
For code=X the part# cannot be duplicate. For any other code there can be duplicate part#. e.g ID 8 row can't be there but ID 6 row is fine. There are several different codes in the table and part# but uniqueness is desired only for one code=X.
ID CODE PART#
1 A R0P98
2 X R9P01
3 A R0P98
4 A R0P44
5 X R0P44
6 A R0P98
7 X T0P66
8 X T0P66
The only way I see is to create a trigger on the table and check for PART# for code=X before insert or update. However, I fear this solution may slow down inserts and updates on this table.
Appreciate your help!
In Oracle, you can create a unique index on an expression for this:
create unique index myidx
on mytable (case when code = 'X' then part# end);

Continue with Id order values after delete some rows

I accidentally deleted some rows from a table, it's just 4 rows, but now when I try to insert the same values again the Id values are different, it's like it's remembering the Id values that had the rows I deleted before and now every time I insert a row the value generated for Id is not the next to the existent sequence... For example:
Id Name
1 Peter
2 Luis
3 Charles
4 John
Let's say I deleted rows with Name value Peter, Luis, Charles and John. When I try to insert the same names again it inserts them but with a different Id..
Id Name
1 Peter
5 Luis
6 Charles
7 John
I can not change the Identity value manually to the old values.. Which is the best solution in this case?
The reason is that auto-incrementing Id's don't automatically reset. This is by design, as you may have the same values references in other tables, which you may not want to delete (although it creates orphaned rows).
The method of resetting the auto-incrementing value differs between databases. For instance, in MySQL, you can run:
ALTER TABLE myTable SET AUTO_INCREMENT=1;
If you AUTOINCREMENT the Primary Key then you can't change the sequence with which you have started.Even if you insert the same name again it does not matter.It will continue from the next number with which it previously ended.
But if you want to give it a number then don't AUTOINCREMENT it,INSERT primary key value like other values you have inserted in the table.
I ended up setting identity_insert to on and entering the Ids manually with the names and then changed the table back to how it was with identity_insert off

Data rows were repeated 4 times when I ( select first 1000 rows) In sql server

I use SQL Server 2014 to create a database and a table and inserted 10 rows of data.
The problem that when I select to 1000 rows, rows was repeated 4 times so they are now 40 rows as you can see in the images
Now I want to ask: why did this happen?
And how to solve that?
And also I want to ask how to find the query that I entered the data in .. I tried script table as > CREATE TO > create new query but it only gives me the table and values
How did you try and delete the rows? Did you write a DELETE statement and specify an id? Given you have 4 sets of rows that you say are unique (I'll take your word for it) and you have an ID column which repeats, you could adapt the following statement to help you.
DELETE TOP (3) FROM dbo.waqf WHERE ID IN (1,2,3,4,5,6,7,8,9,10)
EDIT
I made a mistake: Using the TOP (n) with an IN clause won't work as you might think - I should have tested it a bit. That will simply delete the first n rows in the table where the ID is in the specified range. Really you should loop through each of your unique IDs and issue a DELETE per id. There's probably a better way of doing this but it's early here and my brain isn't working yet.
DECLARE #id INT
SET #id = 1
WHILE #id <= (SELECT MAX(ID) FROM dbo.waqf)
BEGIN
DELETE TOP (3) FROM dbo.waqf WHERE ID = #id
SET #id += 1
END

Updating database records with unique constraint

Given the following simple table structure (SQL Server 2008), I want to be able to maintain uniqueness of my numerical sequence column, but I want to be able to update that value for any given record(s).
CREATE TABLE MYLIST(
ID int NOT NULL IDENTITY(1, 1)
, TITLE varchar(50) NOT NULL
, SEQUENCE int NOT NULL
, CONSTRAINT pk_mylist_id PRIMARY KEY(ID)
, CONSTRAINT uq_mylist_sequence UNIQUE(SEQUENCE)
);
My interface allows me to jumble up the order of the items and I will know prior to doing the update which non-overlapping sequence they should all be in, but how do I perform the update without being confronted with a violation of the unique constraint?
For instance, say I have these records:
ID TITLE SEQUENCE
1 APPLE 1
2 BANANA 2
3 CHERRY 3
And I want to update their sequence numbers to the following:
ID TITLE SEQUENCE
1 APPLE 3
2 BANANA 1
3 CHERRY 2
But really I could be dealing with a couple dozen items. The sequence numbers must not overlap. I've thought about trying to use triggers or temporarily disabling the constraint, but that would seem to create more issues. I am using C# and LINQ-to-SQL, but am open to strictly database solutions.
The obvious way is to write as one batch. Internally, SQL will defer the constraint checks so intermediate uniqueness is irrelevant.
Writing row by row does not make sense and causes the problem you have.
You can change this to write into a temp table, and then "flush" the results at the end, even check uniqueness over the temp table first.
DECLARE #NewSeq TABLE (ID int, NewSeq int)
INSERT #NewSeq (ID, NewSeq) VALUES (1, 3)
INSERT #NewSeq (ID, NewSeq) VALUES (2, 1)
INSERT #NewSeq (ID, NewSeq) VALUES (3, 2)
UPDATE
M
SET
SEQUENCE = NewSeq
FROM
MYLIST M
JOIN
#NewSeq N ON M.ID = N.ID
You could assign them the negative of their correct value, then after all updates have occurred, do a final update where you set SEQUENCE = -SEQUENCE.
It is not very efficient, but since you say you only have a couple dozen items, I doubt the impact would be noticeable. I am also assuming that you can use negative numbers as "magic values" to indicate temporarily mis-assigned values.
If you really have to follow that workflow of inserting without knowing the right order and then having to come back with an update later to set the right order, I'd say your best option is to get rid of the unique constraint because it is causing you more problems than it is worth. Of course, only you know how much that unique constraint is "worth" to your application.