Selecting and inserting (copying rows with partially unique values) - sql

I would like to copy rows in my table to the same table but change the unique values (so i dont get duplicates of the unique). Using MS SQL Server 2008
Table example
ID NAME POS TYPE DATA
XXXXXXXXXXXXXXX_TTTT Something Hefty 0 01DAT 2008-09-29
XXXXXXXXXXXXXXX_WWWW Something Hefty 2 01RAT Random txt
ZZZZZZZZZZZZZZZ_YYYY Something Else 1 01DAF Random value
None of the columns have any keys and all columns are of Varchar data type.
Now what i want to do is to select theese rows and insert them (like a copy paste ish thing) but i want to keep the _YYYY, _TTTT and _WWWW (they are replacements and are unique for each X or Z ID- which means that _TTTT can be the same as _YYYY since X and Z are diffrent) in the ID column but make new XXXXXXXXXXXXXXX and ZZZZZZZZZZZZZZZ part of the ID. Also i want to change the NAME since it has to be unique with the XXXXXXXXXXXXX ID or ZZZZZZZZZZZZZZZ ID. (The X ID has one name and the Z ID has another.)
Here is the statement i try to use (its incomplete since i cant figure it completly out)
insert into Table_name(ID,NAME,POS,TYPE,DATA)
select 'XXXXXXXXXXXXXXX'+substring(ID,15,5), NAME+'(Copy)',POS,TYPE,DATA
from Table_name where NAME='Old name' or NAME='Old name 2'
The 'Old name' and 'Old name 2' part is to be able to pick which NAME that i want to copy (most of times more than 5).
So the help i need with is to make new unique XXXXXXXXXXXXXXX and ZZZZZZZZZZZZZZZ ID's for each name.

I'm not sure if I understood correctly, but what you might need is UPDATE:
UPDATE table_name
SET ID = REPLACE(ID, '_', '')
, NAME = NAME + ' ' + REPLACE(ID, '_', '')
If you can change that table design, you should really do that, for instance create INT type column for ID, add primary key constraint etc.

Related

How can I auto-generate complex identifiers and ensure uniqueness?

I've been handed a very specific business requirement, and I'm having trouble translating it to work within our database.
We have multiple departments, who all deal with what we call files. Each file has a unique identifier, but how this identifier is assigned depends on the department that the file is associated with.
Departments ABC, DEF and GHI need the system to provide them with the next identifier following a pattern... while departments JKL and MNO need to be able to specify their own identifiers.
This is further compounded by the fact that the generated file numbers are semi complex. Their file numbers follow the pattern:
[a-z]{3,4}\d{2}-\d{4}
(A 3 or 4 letter prefix that corresponds to the department with two digits corresponding to the year, a dash followed by a four digit generated number - i.e. ABC13-0001)
The part before the dash is easy to generate... the file table has a mandatory foreign key reference to a department table that has the prefix column, and I can grab the year just as easily. it's the part after the dash that I can't seem to work out.
It's a four digit identifier. Each department needs the next generated ID to be as sequential to their department as possible (I say as sequential as possible, as I'm aware that even identity specifications can leave gaps). On top of that, we need to reset it back to 0001 each year. All of that, while ensuring that there are no duplicates, which is the most important part of all of this.
So, we only have one file table that is used by all of these departments. As such, to be able to handle JKL and MNO, I have the FileNumber field set to varchar(12) with a unique constraint. They can type in whatever they need, so long as it's unique. That just leaves me with how to generate the unique file numbers for the other departments.
My first instinct is to give the file table a surrogate identity primary key to make sure that, even if something goes wrong with the generated file number, that each record is guaranteed a unique identifier.
Then I would create a single row table that has two columns per department, one for a number and one for a date. The number would be the last used number for the 4 digit identifier suffix for a given department (as an int), and the date would be when it was assigned. Storing the date would let me check if the year has changed since the last id was pulled so that I can assign 1, instead of lastid + 1.
Then an insert trigger on the file table would generate the file id using:
The foreign key to the department table to get the department prefix
CONVERT(VARCHAR, YEAR( GETDATE() ) % 100) to pull the current two digit year
A select to the above described utility table to get the last id + 1 (or reseting to 1 if the current year differs from the year of the last updated date).
The trigger would finally update the utility table with the last used id and date.
In theory, I think that would work... and the unique constraint on the file id column would prevent an insert where the generated file id already exists. But it feels so brittle, and I can foresee that unique constraint being a double edged sword that would possibly prevent a department from creating a new file should the trigger fail to update the utility table. After all, if it doesn't, then the next time a file number is generated, it would try to use the same generated id, and fail. There must be a better way.
My other thought was to have a table per department with just an identity integer column and non-null date field with a default of (getdate())... and have the trigger on the file table insert a new row, and use that id. It would also be responsible for deleting all rows in the given department id table and reset the identity come the new year. It feels more secure to me, but then I have 5 utility tables (1 per department that auto-generate ids) with up to 9999 records, just to generate an id.
Am I missing something simple? Am I going about this the right way? I just can't help but think that there must be an easier way. Am I right to try to make the SQL server responsible for this, or should I try doing this in the desktop application that I will build on top of this database?
So, I think it's possible you're overcomplicating this. It's also possible I'm misunderstanding the requirements. I don't believe you need separate tables or anything, you just need to check the existing IDs and increment them. SQLFiddle doesn't seem to be working right now, but here's a method I came up with in my local DB:
create table dept_ids (
id varchar(12) primary key
)
insert into dept_ids values('ABC13-0001')
insert into dept_ids values('DEF13-0001')
insert into dept_ids values('GHI13-0001')
insert into dept_ids values('JKL13-0001')
insert into dept_ids values('ABC13-0002')
declare
#dept varchar(4)
, #year varchar(2)
, #prefix varchar(8)
, #new_seq int
set #dept = 'ABC'
select #year = right(cast(DATEPART(yy, getdate()) as varchar(4)), 2)
set #prefix = #dept + #year + '-'
select #new_seq = isnull(right(max(id), 4), 0) + 1 from dept_ids where id like #prefix + '%'
select new_id = #prefix + right(replicate('0', 4) + cast(#new_seq as varchar(4)), 4)
This handles the different departments of course, as well as the year scenario by using getdate() and an ISNULL check. For the departments that can enter their own sequence values, you can just add a null check for that parameter and skip generating this value if it's present.
If I'm oversimplifying, feel free to let me know and I'll adjust.

SQL insert row with one change

I have this table:
Table1:
id text
1 lala
And i want take first row and copy it, but the id 1 change to 2.
Can you help me with this problem?
A SQL table has no concept of "first" row. You can however select a row based on its characteristics. So, the following would work:
insert into Table1(id, text)
select 2, text
from Table1
where id = 1;
As another note, when creating the table, you can have the id column be auto-incremented. The syntax varies from database to database. If id were auto-incremented, then you could just do:
insert into Table1(text)
select text
from Table1
where id = 1;
And you would be confident that the new row would have a unique id.
Kate - Gordon's answer is technically correct. However, I would like to know more about why you want to do this.
If you're intent is to have the field increment with the insertion of each new row, manually setting the id column value isn't a great idea - it becomes very easy for there to be a conflict with two rows attempting to use the same id at the same time.
I would recommend using an IDENTITY field for this (MS SQL Server -- use an AUTO_INCREMENT field in MySQL). You could then do the insert as follows:
INSERT INTO Table1 (text)
SELECT text
FROM Table1
WHERE id = 1
SQL Server would automatically assign a new, unique value to the id field.

Get values based on newly inserted value using SQL

I want to make filtration on a column after selecting a specific value of another column in the same table, I tried to use #... special character followed by the column's name to get the address of this value.
My SQL statement is like the following :
SELECT ATTRIBUTE FROM TABLE WHERE FIELD = '#FIELDNAME';
If I used a specific value instead of #FIELDNAME, it will work properly but it will be static but I need it to be dynamic based on the selected value.
Create another table which will have the list of values that are in the FIELDNAME and give each record a unique id ,then retrieve the value depending on what you have selected by the name of the new table's field preceded by '#...'
I don't know if that what are you looking for, please let me know.
If no triggers are allowed, do you have any date/time column in the table? Is it possible to have that extra column anyway to see the time of a newly inserted row?
You may have to check the lastest row entered, save its field value into a variable. Then do the select based on the variable value.
Based on the vague last row id you could try the following (it's not pretty). But again, if you have date/time that's more accurate.
select attribute from table
where field = (select field from table
where rowid =(select max(rowid) from table))
;
upate
Do you have the priviledge to set up your insert command as below:
insert into table (id, col1, col2,...) values (1,'something', 'something',...)
returning id into variable; -- you may either save field or id depending on your table
Then you may use this variable to select the records you want.

change ID number to smooth out duplicates in a table

I have run into this problem that I'm trying to solve: Every day I import new records into a table that have an ID number.
Most of them are new (have never been seen in the system before) but some are coming in again. What I need to do is to append an alpha to the end of the ID number if the number is found in the archive, but only if the data in the row is different from the data in the archive, and this needs to be done sequentially, IE, if 12345 is seen a 2nd time with different data, I change it to 12345A, and if 12345 is seen again, and is again different, I need to change it to 12345B, etc.
Originally I tried using a where loop where it would put all the 'seen again' records in a temp table, and then assign A first time, then delete those, assign B to what's left, delete those, etc., till the temp table was empty, but that hasn't worked out.
Alternately, I've been thinking of trying subqueries as in:
update table
set IDNO= (select max idno from archive) plus 1
Any suggestions?
How about this as an idea? Mind you, this is basically pseudocode so adjust as you see fit.
With "src" as the table that all the data will ultimately be inserted into, and "TMP" as your temporary table.. and this is presuming that the ID column in TMP is a double.
do
update tmp set id = id + 0.01 where id in (select id from src);
until no_rows_changed;
alter table TMP change id into id varchar(255);
update TMP set id = concat(int(id), chr((id - int(id)) * 100 + 64);
insert into SRC select * from tmp;
What happens when you get to 12345Z?
Anyway, change the table structure slightly, here's the recipe:
Drop any indices on ID.
Split ID (apparently varchar) into ID_Num (long int) and ID_Alpha (varchar, not null). Make the default value for ID_Alpha an empty string ('').
So, 12345B (varchar) becomes 12345 (long int) and 'B' (varchar), etc.
Create a unique, ideally clustered, index on columns ID_Num and ID_Alpha.
Make this the primary key. Or, if you must, use an auto-incrementing integer as a pseudo primary key.
Now, when adding new data, finding duplicate ID number's is trivial and the last ID_Alpha can be obtained with a simple max() operation.
Resolving duplicate ID's should now be an easier task, using either a while loop or a cursor (if you must).
But, it should also be possible to avoid the "Row by agonizing row" (RBAR), and use a set-based approach. A few days of reading Jeff Moden articles, should give you ideas in that regard.
Here is my final solution:
update a
set IDnum=b.IDnum
from tempimiportable A inner join
(select * from archivetable
where IDnum in
(select max(IDnum) from archivetable
where IDnum in
(select IDnum from tempimporttable)
group by left(IDnum,7)
)
) b
on b.IDnum like a.IDnum + '%'
WHERE
*row from tempimport table = row from archive table*
to set incoming rows to the same IDnum as old rows, and then
update a
set patient_account_number = case
when len((select max(IDnum) from archive where left(IDnum,7) = left(a.IDnum,7)))= 7 then a.IDnum + 'A'
else left(a.IDnum,7) + char(ascii(right((select max(IDnum) from archive where left(IDnum,7) = left(a.IDnum,7)),1))+1)
end
from tempimporttable a
where not exists ( *select rows from archive table* )
I don't know if anyone wants to delve too far into this, but I appreciate contructive criticism...

increase Ids in table

I would like to increase all ids in my table by 1000 cause I need to insert there data from other table with excactly the same ids. What is the best way to do that?
update dbo.table set id = id + 1000
go
The best way to go is to not do that. You have to change all related records as well and if you are using identities it gets even more complicated. If you do anything wrong you will seriousl mess up your data integrity. I would suggest that the data you want to insert is the data that needs to have the values changed and if you need to relate back to the data in another tbale, store the original ID in a new field in the table called something like table2id or database2id. If you can't change the existing table, then you can use a lookup table that has both the old id value and the new one.
Under no circumstances should you attempt something of this nature without taking a backup first.
First as HLGEM it seems to be a bad id (think about your foreign keys on id's you must add 1000 to them to).
Second dbo.table has become sys.tables in Server 2008.
Finally you'll need to find the foreign keys columns with this request :
SELECT name,OBJECT_NAME(object_id)
FROM sys.columns
WHERE name like '%id' or name like 'id%'
--depends on where is 'id' in your columns names
name : the column name, OBJECT_NAME : the table name
And update the whole thing (with a tricky request that should looks like this one, but i didn't test with the "update" command) :
CREATE TABLE #TablesWithIds (
columnName varchar(100),
tableName varchar(100)
)
Insert into #TablesWithIds
SELECT name as columnName,OBJECT_NAME(object_id) as tableName
FROM sys.columns
WHERE name like '%id%'
update #TablesWithIds.tableName set #TablesWithIds.columnName = #TablesWithIds.columnName +1000
drop table #TablesWithIds