I have a table named tblSample which has columns ID, PID etc. I want to auto generate those two columns with a specific pattern.
For example:
ID PID
------ ------
ABC001 PAB001
ABC002 PAB002
ABC003 PAB003
ABC004 PAB004
| |
| |
ABC999 PAB999
As you can see, the pattern 'ABC' in ID and 'PAB' in PID is the same. How can I insert those records into a table automatically and the range between those three digits after 'ABC' or 'PAB' is 001-999?
My suggestion is to create table structure as below with one identity column as testID and other computed by using that column ID and PID:
CREATE TABLE #tmpOne(testID INT IDENTITY (1,1),
ID AS ('ABC'+ (CASE WHEN len(testID) <=3 THEN CAST(RIGHT(0.001*testID, 3) AS VARCHAR) ELSE CAST(testID AS VARCHAR) END)),
Ename VARCHAR(20))
INSERT INTO #tmpOne(Ename)
SELECT 'Test'
SELECT * FROM #tmpOne
CREATE TABLE #tt(ID VARCHAR(100),PID VARCHAR(100))
GO
INSERT INTO #tt(ID,PID)
SELECT 'ABC'+RIGHT('000'+LTRIM(a.ID),3),'PAB'+RIGHT('000'+LTRIM(a.ID),3) FROM (
SELECT ISNULL(MAX(CASE WHEN SUBSTRING(t.id,4,LEN(ID))> SUBSTRING(t.id,4,LEN(PID)) THEN SUBSTRING(t.id,4,LEN(ID)) ELSE SUBSTRING(t.id,4,LEN(PID)) END )+1,1) AS id
FROM #tt AS t
) AS a
GO 999
Related
I am working in SQL Server 2017, and I have a table of the form:
tbl_current
COL1 COL2
-----------
A 1
B 3
C 56
which I want to periodically insert into the table tbl_release.
This table would have an extra ID column, which I'd like to auto-increment with each "batch insertion". For example, let's say I perform the the ingestion of tbl_current into tbl_release, it would look like this:
tbl_release
ID COL1 COL2
----------------
1 A 1
1 B 3
1 C 56
Now, let's say I perform another ingestion with the same data, it'd look like:
tbl_release
ID COL1 COL2
----------------
1 A 1
1 B 3
1 C 56
2 A 1
2 B 3
2 C 56
What is the best way to achieve this? Is there some SQL Server feature that would allow to achieve this, or do I need to run some sub-queries?
I'd personallly use a sequence for this. Assuming the insert into your ephemeral table is done, it'd looks omething like this:
declare #ID int = next value for sequence dbo.mySequence;
insert into tbl_release
(ID, col1, col2)
select #ID, col1, col2
from tbl_current;
You can try this using MAX() function as shown below.
Declare #maxId int
set #maxId = (Select isnull(id, 0) from tbl_Current)
set #maxId = #maxId + 1
--Now to insert
insert into tbl_release values (#maxId, <Column1Value>, <Column2Value>)
For multiple insert you can try this
INSERT INTO tbl_release
SELECT #maxId, col1, col2 FROM tbl_Current
If your table's Id column is identity then you can also use the Scope_Identity to get the max value of Id column.
Your id is really an object. I would strongly suggest that you give it a full table:
create table batches (
batch_id int identity(1, 1) primary key,
batch_start_date datetime,
. . .
);
Then, your existing table should be structured as:
create table releases (
release_id int identity(1, 1) primary key,
batch_id int not null references batches(batch_id),
col1 char(1),
col2 int
);
That way, your database has referential integrity.
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).
This my table1:
Name Description
john student
dom teacher
I need to use SELECT * INTO to transfer it to another table (table2) but I want it with a new column named Auto which is auto-incremented.
Which will look like this:
Name Description Auto
John Student 1
Dom Teacher 2
Current Code: SELECT * INTO table2 FROM table1
Use ROW_NUMBER to add sequential number starting from 1.
SELECT *,
Auto = ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
INTO table2
FROM table1
The accepted answer has additional convenience when breaking one table into several smaller ones with the exact number of rows. If necessary, it is possible to remove the column used for autoincrement.
SELECT *,
ID = ROW_NUMBER() OVER(ORDER BY ( SELECT NULL ))
INTO #Table2
FROM Table1
DECLARE #start INT, #end INT;
SET #start = 1;
SET #end = 5000000;
SELECT *
INTO Table3
FROM #Table2
WHERE ID BETWEEN #start AND #end;
ALTER TABLE Table3 DROP COLUMN ID;
You can use an identity field for this, that's what they're for. The logic of the identity(1,1) means that it will start at the number 1 and increment by 1 each time.
Sample data;
CREATE TABLE #OriginalData (Name varchar(4), Description varchar(7))
INSERT INTO #OriginalData (Name, Description)
VALUES
('John','student')
,('Dom','teacher')
Make a new table and insert the data into it;
CREATE TABLE #NewTable (Name varchar(4), Description varchar(7), Auto int identity(1,1))
INSERT INTO #NewTable (Name, Description)
SELECT
Name
,Description
FROM #OriginalData
Gives the results as;
Name Description Auto
John student 1
Dom teacher 2
If you ran the insert a couple more times your results would look like this;
Name Description Auto
John student 1
Dom teacher 2
John student 3
Dom teacher 4
John student 5
Dom teacher 6
Table 1 - Deal ID, REF NOS, Type, Papa ID
Table 2 - Deal ID, Type
Making a column in a new view called Method used. The way the field is to be set is as follows ( 4 conditions);
If Deal ID from table 1 Exists in Table 2 and Type is not Null from Table 2.
Set Method used to be Y
If Deal ID does not exist in Table 1 and Type does not contain 27,42 or 55 in Table 1.
Set Method used to be Y
If Papa ID is null from Table 1, and Type does not contain 27,42 or 55 in Table 1.
Set Method used to be Y
Else
Set to N
Started it and thought wow!..
create view Master as (
select Deal ID, REF NOS, Type, Papa ID
[Method used]=
Case
When
from Table 1 A
)
Something like this may work (assuming that these tables join on DealId). Note, I've removed spaces from some of your column names that you showed in your question.
Given these tables:
CREATE TABLE #Table1 (DealId INT, RefNos VARCHAR(100), [Type] VARCHAR(100), PapaId INT);
CREATE TABLE #Table2 (DealId INT, [Type] VARCHAR(100));
view example:
WITH DealIds AS (
SELECT DealId FROM #Table1
UNION
SELECT DealId FROM #Table2
)
SELECT
CASE
-- If Deal ID from table 1 Exists in Table 2 and Type is not Null from Table 2.
-- Set Method used to be Y
WHEN t1.DealId IS NOT NULL AND t2.DealId IS NOT NULL AND t2.[Type] IS NOT NULL THEN 'Y'
-- If Deal ID does not exist in Table 1 and Type does not contain 27,42 or 55 in Table 1.
-- Set Method used to be Y
-- Note: it is is redundant to have the type condition if DealId is the PK.
WHEN t1.DealId IS NULL AND t1.[Type] NOT IN (27, 42, 55) THEN 'Y'
-- If Papa ID is null from Table 1, and Type does not contain 27,42 or 55 in Table 1.
-- Set Method used to be Y
WHEN t1.PapaId IS NULL AND t1.[Type] NOT IN (27,42, 55) THEN 'Y'
-- Else
-- Set to N
ELSE 'N'
END AS MethodUsed
FROM DealIds d
LEFT JOIN #Table1 t1 ON d.DealId = t1.DealId
LEFT JOIN #Table2 t2 ON d.DealId = t2.DealId
I have a data in one table. I need to copy it to another table. One of the column is text delimited string. So what I'm thinking to select all columns insert get indentity value and with subquery to split based on delimiter and insert it to another table.
Here is the data example
ID Name City Items
1 Michael Miami item|item2|item3|item4|item5
2 Jorge Hallandale item|item2|item3|item4|item5
copy Name, City to one table get identity
and split and copy Items to another table with Identity Column Value
So output should be
Users table
UserID Name City
1 Michael Miami
2 Jorge Hallandale
...
Items table
ItemID UserID Name
1 1 Item
2 1 Item2
3 1 Item3
4 1 Item4
5 2 Item
6 2 Item2
7 2 Item3
8 2 Item4
Not really sure how to do it with T-SQL. Answers with examples would be appreciated
You may create you custom function to split the string in T-Sql. You could then use the Split function as part of a JOIN with your base table to generate the final results for your INSERT statement. Have a look at this post. Hope this help.
You can do this using xml and cross apply.
See the following:
DECLARE #t table (ID int, Name varchar(20), City varchar(20), Items varchar(max));
INSERT #t
SELECT 1,'Michael','Miami' ,'item|item2|item3|item4|item5' UNION
SELECT 2,'Jorge' ,'Hallandale','item|item2|item3|item4|item5'
DECLARE #u table (UserID int identity(1,1), Name varchar(20), City varchar(20));
INSERT #u (Name, City)
SELECT DISTINCT Name, City FROM #t
DECLARE #i table (ItemID int identity(1,1), UserID int, Name varchar(20));
WITH cte_Items (Name, Items) as (
SELECT
Name
,CAST(REPLACE('<r><i>' + Items + '</i></r>','|','</i><i>') as xml) as Items
FROM
#t
)
INSERT #i (UserID, Name)
SELECT
u.UserID
,s.Name as Name
FROM
cte_Items t
CROSS APPLY (SELECT i.value('.','varchar(20)') as Name FROM t.Items.nodes('//r/i') as x(i) ) s
INNER JOIN #u u ON t.Name = u.Name
SELECT * FROM #i
See more here:
http://www.kodyaz.com/articles/t-sql-convert-split-delimeted-string-as-rows-using-xml.aspx
Can you accomplish this with recursion? My T-SQL is rusty but this may help send you in the right direction:
WITH CteList AS (
SELECT 0 AS ItemId
, 0 AS DelimPos
, 0 AS Item_Num
, CAST('' AS VARCHAR(100)) AS Item
, Items AS Remainder
FROM Table1
UNION ALL
SELECT Row_Number() OVER(ORDER BY UserID) AS ItemId
, UserID
, CASE WHEN CHARINDEX('|', Remainder) > 0
THEN CHARINDXEX('|', Remainder)
ELSE LEN(Remainder)
END AS dpos
, Item_num + 1 as Item_Num
, REPLACE(Remainder, '|', '') AS Element
, right(Remainder, dpos+1) AS Remainder
FROM CteList
WHERE dpos > 0
AND ItemNum < 20 /* Force a MAX depth for recursion */
)
SELECT ItemId
, Item
FROM CteList
WHERE item_num > 0
ORDER BY ItemID, Item_Num