I created the table 'test':
create table test
(
column1 varchar(10),
column2 varchar(10),
)
and added the values
insert into test values('value1','value2')
insert into test values('value1','value2')
But now I need to create a column that will be a primary key, but I can not use the 'Identity' command because the control will be done by the application.
alter table test add ID int
How do I populate values that are null so they stay in sequence? Where as they are null.
result from 'select * from test':
column1 column2 ID
value1 value2 NULL
value1 value2 NULL
Try this
;WITH cte
AS
(
SELECT *, ROW_NUMBER() OVER(ORDER BY column1, column2) AS RowNum FROM test
)
UPDATE cte
SET iID = RowNum
Now check your table records
SELECT * FROM test
You can do this:
add a nullable column Id
update Id with a value
set Id as not null
make Id the primary key.
create table test (
column1 varchar(10)
, column2 varchar(10)
);
insert into test values
('value1','value2')
,('value1','value2');
alter table test add Id int null;
update t set Id = rn
from (
select *
, rn = row_number() over (order by column1, column2)
from test
) as t;
alter table test alter column Id int not null;
alter table test
add constraint pk_test primary key clustered (Id);
select * from test;
test setup: http://rextester.com/DCB57058
results:
+---------+---------+----+
| column1 | column2 | Id |
+---------+---------+----+
| value1 | value2 | 1 |
| value1 | value2 | 2 |
+---------+---------+----+
Add temp identity column, copy values from this column to ID, then drop temp column:
CREATE TABLE #test
(
column1 varchar(10),
column2 varchar(10),
)
INSERT INTO #test
VALUES
('aa','aa'),
('bb','bb')
ALTER TABLE #test
ADD ID INT
ALTER TABLE #test
ADD TempID INT IDENTITY(1,1)
UPDATE t
SET
t.ID = t.TempID
FROM #test t
ALTER TABLE #test
DROP COLUMN TempID
SELECT *
FROM #test t
DROP TABLE #test
In the first place, you can't create a PK with NULL values (check MSDN here).
If you want to make your application to create your PK value, you have to give it at INSERT time or give some "Default" value(s) before your application edit it. The second option is dangerous for various reasons (trust your application to ensure unicity? how will you make a lot of INSERT in a short time? etc).
I have two table Table1 and Table2 and structure of table as
Table1
Primary Key | Name
Table2
Primary Key | Table1_Id_pk | Status - true/false value
When I insert data into Table2 I want to automatically transfer that data in table1 from Table2 which have Status false.
You can create AFTER INSERT trigger:
CREATE TRIGGER DataMigration
ON Table2
AFTER INSERT
AS
BEGIN
INSERT INTO Table1
SELECT *
FROM TAble2
WHERe Status = 'false'
END
GO
Check this example, use ##identity to get inserted row-id and use that id for child table.
declare #t1 table (pk int identity(1,1) not null , name varchar(50) )
declare #t2 table (pk int identity(1,1) not null , t1pk int, status bit )
declare #new_table1Id int
insert into #t1 values( 'ajay')
set #new_table1Id = ##IDENTITY -This gives you last inserted id of #t1
insert into #t2 values( #new_table1Id , 0)
select * from #t1
select * from #t2
##IDENTITY official documentation
I have a problem with implementing DB. I have 2 tables:
CREATE TABLE TAB1
(
TAB1_ID INT NOT NULL PRIMARY KEY,
TAB1_BOOL VARCHAR(4) NOT NULL CHECK (TAB1_BOOL IN('OPT1', 'OPT2'))
);
CREATE TABLE TAB2
(
TAB2_ID INT NOT NULL
);
I would like to make TAB2_ID as foreign key of TAB1_ID, but TAB2_ID can be only these TAB1_IDs which rows in table TAB1 are marked with TAB1_BOOL == OPT1. For example:
TAB1 contains 2 rows:
1. 'TAB1_ID==1' 'TAB1_BOOL==OPT1',
2. 'TAB1_ID==2' 'TAB1_BOOL==OPT2'.
Now, statement like:
INSERT INTO TAB2 (TAB2_ID) VALUES (2);
should be rejected because row with TAB1_ID==2 is marked with OPT2
Is it possible to make this in Oracle SQL ?
This can be achieved by using a trigger:
CREATE TABLE TAB1 (
TAB1_ID INT NOT NULL PRIMARY KEY,
TAB1_BOOL VARCHAR(4) NOT NULL CHECK (TAB1_BOOL IN('OPT1', 'OPT2'))
);
CREATE TABLE TAB2 (
TAB2_ID INT NOT NULL,
FOREIGN KEY (TAB2_ID) REFERENCES TAB1 (TAB1_ID)
);
CREATE OR REPLACE TRIGGER CHECK_TAB2_ID
BEFORE UPDATE OR INSERT ON TAB2 FOR EACH ROW
DECLARE
CURSOR CHECK_CURSOR IS
SELECT TAB1_BOOL
FROM TAB1
WHERE TAB1_ID = :new.TAB2_id;
V_TAB1_BOOL VARCHAR(4);
BEGIN
OPEN CHECK_CURSOR;
FETCH CHECK_CURSOR INTO V_TAB1_BOOL;
IF (V_TAB1_BOOL <> 'OPT1') THEN
CLOSE CHECK_CURSOR;
raise_application_error(10000, 'Wrong value in TAB1');
END IF;
CLOSE CHECK_CURSOR;
END;
INSERT INTO TAB1 VALUES (1, 'OPT1');
INSERT INTO TAB1 VALUES (2, 'OPT2');
INSERT INTO TAB2 (TAB2_ID) VALUES (1);
There is still a small error in the trigger above. I have currently no access to an Oracle database, so I can hardy fix it. Here's my Fiddle.
p.s.: ok, just a ; missing in the Fiddle - here's an update.
Suppose I have a simple table:
CREATE TABLE user(
id INT NOT NULL PRIMARY KEY,
name VARCHAR(32) NOT NULL,
)
Is there a way to alter this table so id will become AUTO_INCREMENT field?
I tried the following with no luck:
ALTER TABLE (no such syntax)
Creating another table with auto increment ID, and copying the data from the original one (didn't work because of the error: Cannot insert into or update IDENTITY/AUTO_INCREMENT column "id")
Thanks!
I would try to just rank the rows, and use the sequence for future inserts.
\set AUTOCOMMIT 'on'
CREATE TABLE t1 (
val char(1)
);
INSERT INTO t1 VALUES ('a');
INSERT INTO t1 VALUES ('b');
INSERT INTO t1 VALUES ('c');
INSERT INTO t1 VALUES ('d');
CREATE TABLE t2 (
id int,
val char(1)
);
INSERT INTO t2 (val, id)
SELECT val, RANK() OVER (ORDER BY val) as id
FROM t1;
SELECT * FROM t2;
We get:
id | val
----+-----
1 | a
3 | c
2 | b
4 | d
Success!
Let's prepare the table for future inserts:
-- get the value to start sequence at
SELECT MAX(id) FROM t2;
-- create the sequence
CREATE SEQUENCE seq1 START 5;
-- syntax as of 6.1
-- modify the column to add next value for future rows
ALTER TABLE t2 ALTER COLUMN id SET DEFAULT NEXTVAL('seq1');
Quick test:
INSERT INTO t2 (val) VALUES ('e');
INSERT INTO t2 (val) VALUES ('f');
SELECT * FROM t2;
We get:
id | val
----+-----
4 | d
2 | b
3 | c
6 | f
1 | a
5 | e
Hope this helps.
I'm not that great with SQL Server, but I'm trying to do some behind the scenes work to create some functionality that our EMR system lacks - copying forms (and all their data) between patients.
In SQL Server 2008 R2 I have three tables that deal with these forms that have been filled out:
**Table 1**
encounter_id patient_id date time etc etc etc etc
1234 112233 2014-01-02 14:25:01:00 a b c d
**Table 2**
encounter_id page recorded_on recorded_by etc etc
1234 1 2014-01-02 134 asdf asdf
1234 2 2014-01-02 134 jkl; jkl;
**Table 3**
encounter_id page keyname keyvalue
1234 1 key1 aaa
1234 1 key2 bbb
1234 1 key3 ccc
1234 1 key4 ddd
1234 2 key5 eee
1234 2 key6 fff
1234 2 key7 ggg
As you can see, they all match together with the encounter_id, which is linked to the patient_id (In the first table).
What I'm trying to be able to do is copy all the rows in these three tables for a particular encounter_id back into the same table they come from, but with a different (system generated) encounter_id for a patient_id that I would specify. In essence, copying the form from one patient to another.
Any help on this is greatly appreciated.
I always like creating sample tables in [tempdb] so that the syntax is correct. I created tables [t1], [t2], and [t3]. There are primary and foreign keys.
If you have a well developed schema, ERD (entity relationship diagram) http://en.wikipedia.org/wiki/Entity-relationship_diagram , these relationships should be in place.
-- Playing around
use tempdb
go
--
-- Table 1
--
-- Remove if it exists
if object_id('t1') > 0
drop table t1
go
-- Create the first table
create table t1
(
encounter_id int,
patient_id int,
the_date date,
the_time time,
constraint pk_t1 primary key (encounter_id)
);
go
-- Add one row
insert into t1 values (1234, 112233, '2014-01-02', '14:25:01:00');
go
-- Show the data
select * from t1
go
--
-- Table 2
--
-- Remove if it exists
if object_id('t2') > 0
drop table t2
go
-- Create the second table
create table t2
(
encounter_id int,
the_page int,
recorded_on date,
recorded_by int,
constraint pk_t2 primary key (encounter_id, the_page)
);
go
-- Add two rows
insert into t2 values
(1234, 1, '2014-01-02', 134),
(1234, 2, '2014-01-02', 134);
go
-- Show the data
select * from t2
go
--
-- Table 3
--
-- Remove if it exists
if object_id('t3') > 0
drop table t3
go
-- Create the third table
create table t3
(
encounter_id int,
the_page int,
key_name1 varchar(16),
key_value1 varchar(16),
constraint pk_t3 primary key (encounter_id, the_page, key_name1)
);
go
-- Add seven rows
insert into t3 values
(1234, 1, 'key1', 'aaa'),
(1234, 1, 'key2', 'bbb'),
(1234, 1, 'key3', 'ccc'),
(1234, 1, 'key4', 'ddd'),
(1234, 2, 'key5', 'eee'),
(1234, 2, 'key6', 'fff'),
(1234, 2, 'key7', 'ggg');
go
-- Show the data
select * from t3
go
--
-- Foreign Keys
--
alter table t2 with check
add constraint fk_t2 foreign key (encounter_id)
references t1 (encounter_id);
alter table t3 with check
add constraint fk_t3 foreign key (encounter_id, the_page)
references t2 (encounter_id, the_page);
Here comes the fun part, a stored procedure to duplicate the data.
--
-- Procedure to duplicate one record
--
-- Remove if it exists
if object_id('usp_Duplicate_Data') > 0
drop procedure t1
go
-- Create the procedure
create procedure usp_Duplicate_Data #OldId int, #NewId int
as
begin
-- Duplicate table 1's data
insert into t1
select
#NewId,
patient_id,
the_date,
the_time
from t1
where encounter_id = #OldId;
-- Duplicate table 2's data
insert into t2
select
#NewId,
the_page,
recorded_on,
recorded_by
from t2
where encounter_id = #OldId;
-- Duplicate table 3's data
insert into t3
select
#NewId,
the_page,
key_name1,
key_value1
from t3
where encounter_id = #OldId;
end
Last but not least, we have to call the stored procedure to make sure it works.
-- Sample call
exec usp_Duplicate_Data 1234, 7777
In summary, I did not add any error checking or accounted for a range of Id's. I leave these tasks for you to learn.
Made a little fiddle as an example, here (link)
The solution is perhaps needlessly complex but it offers a good variety of other useful stuff as well, I just wanted to test how to build that dynamically. The script does print out the commands, making it relatively easy to remove the TSQL and just produce the plain-SQL to do as you wish.
What it does, is that it requires an encounter_id, which it will then use to dynamically fetch the columns (with the assumption that encounter_id is the PK for TABLE_1) to insert a new record in TABLE_1, store the inserted.encounter_id value, and use that value to fetch and copy the matching rows from TABLE_2 and TABLE_3.
Basically, as long as the structure is correct (TABLE_1 PK is encounter_id which is an identity type), you should be able to just change the table names referenced in the script and it should work directly regardless of which types of columns (and how many of them) your particular tables have.
The beef of the script is this:
/* Script begins here */
DECLARE #ENCOUNTER_ID INT, #NEWID INT, #SQL VARCHAR(MAX), #COLUMNS VARCHAR(MAX)
IF OBJECT_ID('tempdb..##NEW_ID') IS NOT NULL
DROP TABLE ##NEW_ID
CREATE TABLE ##NEW_ID (ID INT)
/* !!! SET YOUR DESIRED encounter_id RECORDS TO BE COPIED, HERE !!! */
SET #ENCOUNTER_ID = 1234
IF EXISTS (SELECT TOP 1 1 FROM TABLE_1 WHERE encounter_id = #ENCOUNTER_ID)
BEGIN
SELECT #COLUMNS = COALESCE(#COLUMNS+', ', 'SELECT ')+name
FROM sys.columns WHERE OBJECT_NAME(object_id) = 'TABLE_1' AND name <> 'encounter_id'
SET #COLUMNS = 'INSERT INTO TABLE_1 OUTPUT inserted.encounter_id INTO ##NEW_ID '+#COLUMNS+' FROM TABLE_1 WHERE encounter_id = '+CAST(#ENCOUNTER_ID AS VARCHAR(25))
EXEC(#COLUMNS)
PRINT(#COLUMNS)
SELECT TOP 1 #NEWID = ID, #COLUMNS = NULL FROM ##NEW_ID
SELECT #COLUMNS = COALESCE(#COLUMNS+', ', '')+name
FROM sys.columns WHERE OBJECT_NAME(object_id) = 'TABLE_2'
SET #COLUMNS = 'INSERT INTO TABLE_2 ('+#COLUMNS+') SELECT '+REPLACE(#COLUMNS,'encounter_id',''+CAST(#NEWID AS VARCHAR(25))+'')
+' FROM TABLE_2 WHERE encounter_id = '+CAST(#ENCOUNTER_ID AS VARCHAR(25))
EXEC(#COLUMNS)
PRINT(#COLUMNS)
SET #COLUMNS = NULL
SELECT #COLUMNS = COALESCE(#COLUMNS+', ', '')+name
FROM sys.columns WHERE OBJECT_NAME(object_id) = 'TABLE_3'
SET #COLUMNS = 'INSERT INTO TABLE_3 ('+#COLUMNS+') SELECT '+REPLACE(#COLUMNS,'encounter_id',''+CAST(#NEWID AS VARCHAR(25))+'')
+' FROM TABLE_3 WHERE encounter_id = '+CAST(#ENCOUNTER_ID AS VARCHAR(25))
EXEC(#COLUMNS)
PRINT(#COLUMNS)
IF OBJECT_ID('tempdb..##NEW_ID') IS NOT NULL
DROP TABLE ##NEW_ID
END
declare #oldEncounterID int
set #oldEncounterID = 1234
declare #newEncounterID int
set #newEncounterID = 2345
insert into table1(encounter_id, patient_id, date, time, etc)
select newEncounterID, patient_id, date, time, etc
from table1 where encounter_id = oldEncounterID
and so on... problem with this approach you must know in advantage what all the columns are, and if they change you may change the columns accordingly
Another approach:
declare #oldEncounterID int
set #oldEncounterID = 1234
declare #newEncounterID int
set #newEncounterID = 2345
select * into #table1 from table1 where encounter_id = oldEncounterID
update #table1 set encounter_id = newEncounterID
insert into table1 select * from #table1
and so on... this second approach however may need a little adjustment if there is an identity column then you'll have to set identity_insert to on
Psuedo code, not tested:
DECLARE #patient_id INT, #date datetime, #time ??
SET #patient_id = 112244 --your patient id
INSERT INTO [**Table 1**] (patient_id, date, time, etc, etc, etc, etc)
VALUES (#patient_id, #date, #time, 'a', 'b', 'c', 'd')
DECLARE #encounter_id int
SET #encounter_id = SCOPE_IDENTITY -- or select #encounter_id = encounter_id from [**Table 1**] where patientId = #patient_id
INSERT INTO [**Table 2**] (encounter_id, page, recorded_on, recorded_by, etc, etc2)
SELECT #encounter_id, page, recorded_on, recorded_by, etc, etc2
FROM [**Table 2**]
WHERE encounter_id = 1234
INSERT INTO [**Table 3**] (encounter_id, page, keyname, keyvalue)
SELECT #encounter_id, page, keyname, keyvalue
FROM [**Table 3**]
WHERE encounter_id = 1234