How to pick random things which are conseq in table - sql-server

create table TAB
(
id int,
Name Char(1)
);
insert into TAB(ID,NAME) values(1,'A')
insert into TAB(ID,NAME) values(1,'B')
insert into TAB(ID,NAME) values(2,'C')
insert into TAB(ID,NAME) values(2,'A')
insert into TAB(ID,NAME) values(2,'B')
insert into TAB(ID,NAME) values(3,'C')
insert into TAB(ID,NAME) values(3,'B')
this is my table and values, without using id column in where condition i need to get c,b and 3 alone from the table

Without the use of TOP / MAX or a WHERE clause :-
SET ROWCOUNT 2; -- Limit the query to just 2 rows
IF OBJECT_ID('tempdb..#tmp','U') IS NOT NULL DROP TABLE #tmp; -- Ensure #tmp table doesn't already exist
SELECT ID,Name,RANK() OVER (ORDER BY id DESC) as Rnk INTO #tmp FROM TAB
SELECT ID,Name FROM #tmp

Related

T-SQL insert and update foreign key without cursor

I have two tables in MS SQL:
CREATE TABLE Table1 (ID INT IDENTITY(1,1) NOT NULL, TEXTVal VARCHAR(100), Table2Id int)
insert into Table1 (TEXTVal) values('aaa');
insert into Table1 (TEXTVal) values('bbb'); insert into Table1 (TEXTVal) values('ccc');
CREATE TABLE Table2 (ID INT IDENTITY(1,1) NOT NULL, TEXTVal VARCHAR(100), Table2Id int)
Id are identity columns. I want to copy TEXTVal values from Table1 to Table2:
INSERT INTO Table2 (TEXTVal)
SELECT TEXTVal FROM Table1
where TEXTVal <> 'ccc'
and after that update column Table2Id in Table1 with appropriate values of Id from Table2. I can do this with cursor and SCOPE_IDENTITY().
I am just wondering, is there a way to do it without cursor in T-SQL?
As Jeroen stated in comments, you'll want to use OUTPUT. In the following example if you don't have an AdventureWorks database, just use a test database. You should be able to copy/paste this and just run it to see it in action!
USE AdventureWorks;
GO
----Creating the table which will store permanent table
CREATE TABLE TestTable (ID INT, TEXTVal VARCHAR(100))
----Creating temp table to store ovalues of OUTPUT clause
DECLARE #TmpTable TABLE (ID_New INT, TEXTVal_New VARCHAR(100),ID_Old INT, TEXTVal_Old VARCHAR(100))
----Insert values in real table
INSERT TestTable (ID, TEXTVal)
VALUES (1,'FirstVal')
INSERT TestTable (ID, TEXTVal)
VALUES (2,'SecondVal')
----Update the table and insert values in temp table using Output clause
UPDATE TestTable
SET TEXTVal = 'NewValue'
OUTPUT Inserted.ID, Inserted.TEXTVal, Deleted.ID, Deleted.TEXTVal INTO #TmpTable
WHERE ID IN (1,2)
----Check the values in the temp table and real table
----The values in both the tables will be same
SELECT * FROM #TmpTable
SELECT * FROM TestTable
----Clean up time
DROP TABLE TestTable
GO
ResultSet:
TmpTable:
ID_New TextVal_New ID_Old TextVal_Old
——————— ——————— ——————— ———————
1 NewValue 1 FirstVal
2 NewValue 2 SecondVal
Original Table:
ID TextVal
——————— ———————
1 NewValue
2 NewValue
As you can see it is possible to capture new values, and the values you are updating. In this example I'm just stuffing them into a table variable but you could do whatever you'd like with them. :)

How to autoincrement the id without identity?

I'm trying do to a bulk insert from another table in sql server. My query is currently like that :
INSERT INTO Table1(Id, Value)
SELECT ??, Value
FROM Table2;
Now, my problem is obviously by what I replace ??. Id is an integer column without an identity property. I would like that for each inserted row, Id take the current max(Id) + 1.
Can I do that directly in my insert command?
If you were using a newer version of SQL Server (2008+) you could try ROW_NUMBER():
DECLARE #BASE INT
SET #BASE = (SELECT IsNull(MAX(ID),0) FROM Table1)
INSERT INTO Table1(Id, Value)
SELECT
#BASE + ROW_NUMBER() OVER (ORDER BY Value) ID,
Value
FROM Table2;
SQL Fiddle
Since you are using SQL Server 2000, you could try like bellow:
DECLARE #BASE INT
SET #BASE = (SELECT IsNull(MAX(ID),0) FROM Table1)
INSERT INTO Table1(Id, Value)
SELECT
#BASE + (SELECT COUNT(*) FROM Table2 AS i2 WHERE i2.Value <= a.Value),
a.Value
FROM Table2 a
But it will only works if Value in Table2 is unique
SQL Fiddle
If Table2 has a primary key (field PK), then you could use:
INSERT INTO Table1(Id, Value)
SELECT
#BASE + (SELECT COUNT(*) FROM Table2 AS i2 WHERE i2.PK <= a.PK),
a.Value
FROM Table2 a
Here is one wicked way.
We create a temp table with identity to generate new ids. This way we avoid the while loop.
DECLARE #CurrentMaxID INT,
#DynamicQuery NVARCHAR(MAX)
--TODO : Acquired table lock here on table1
SELECT #FirstNextID = ISNULL(MAX(Id), 0)
FROM Table1 --WITH(TABLOCK)
CREATE TABLE #TempTableWithID( Table2Id INT,
Table1FuturId INT IDENTITY(1, 1))
INSERT INTO #TempTableWithID(Table2Id)
SELECT Id --Here we use identity to generate table1 futur id
FROM Table2
INSERT INTO Table1(Id, value)
SELECT Temp.Table1FuturId + #FirstNextID,
Table2.Value
FROM Table2
INNER JOIN #TempTableWithID AS Temp ON Table2.Id = Temp.Table2Id
--TODO : release table lock here on table1
DROP TABLE #TempTableWithID
If I'm understanding you correctly, this should work.
CREATE TABLE #tbl1 (ID int, Value float)
CREATE TABLE #tbl2 (ID int, Value float)
INSERT INTO #tbl2 values (4, 2.0)
INSERT INTO #tbl2 values (8, 3.0)
INSERT INTO #tbl2 values (6, 4.0)
INSERT INTO #tbl1 values (1,1.0)
INSERT INTO #tbl1 values (3,3)
INSERT INTO #tbl1 values (9,3)
/*meat and potatoes start*/
INSERT INTO #tbl1(Id, Value)
SELECT (SELECT MAX(ID) FROM #tbl1) + ROW_NUMBER() OVER (ORDER BY Value) ID, Value
FROM #tbl2;
/*meat and potatoes end*/
Select * From #tbl1
drop table #tbl1
drop table #tbl2
Why not IDENT_CURRENT() ?
SELECT IDENT_CURRENT('yourtablename')
It gives you the next ID reference. But this only works if the ID column has IDENTITY turned on.
OR you can try a SEQUENCE and the NEXT VALUE FOR.
i.e.
CREATE TABLE Test.TestTable
(CounterColumn int PRIMARY KEY,
Name nvarchar(25) NOT NULL) ;
GO
INSERT Test.TestTable (CounterColumn,Name)
VALUES (NEXT VALUE FOR Test.CountBy1, 'Syed') ;
GO
SELECT * FROM Test.TestTable;
GO

sqlserver assigning last inserted Id to another column in one query

when this query is executed
DECLARE #Temp TABLE (ID INT IDENTITY,Name VARCHAR(50),ID2 INT NULL)
INSERT INTO #Temp ([Name]) VALUES ('Ali')
UPDATE #Temp SET ID2= (SELECT SCOPE_IDENTITY()) WHERE [ID]=(SELECT SCOPE_IDENTITY())
INSERT INTO #Temp ([Name]) VALUES ('Veli')
UPDATE #Temp SET ID2= (SELECT SCOPE_IDENTITY()) WHERE [ID]=(SELECT SCOPE_IDENTITY())
SELECT * FROM #Temp
We can get this table
ID-NAME-ID2
1 - Ali - 1
2 - Veli - 2
is there a way to do this in one insert query ( Assigning inserted id to another column without using idendity property in that column) ?
thanks a lot.
You want to make it a computed column like below
create TABLE Temp(ID INT IDENTITY,Name
VARCHAR(50),
ID2 AS ID PERSISTED);
Then insert rows ... your ID values will be persisted in ID2 column
INSERT INTO Temp ([Name])
VALUES ('Ali');
INSERT INTO Temp ([Name])
VALUES ('Veli');
INSERT INTO Temp ([Name])
VALUES ('Neli');
Which will results in
See a demo fiddle here http://sqlfiddle.com/#!3/59fca/1
EDIT:
If you can't change your table structure then the only way insert ID value to ID2 column is the way you are currently doing it cause in same insert statement the identity value is still not available and so it will be null.

Need T-SQL Query for Groups and Islands

create table #sample (rowguid int identity ,id_frm int ,id_to int)
insert into #sample values( 1,5)
insert into #sample values( 7,13)
insert into #sample values( 17,20)
In the above table I have values starting Id and Ending Id. I need to prepare a table which has all the numbers falls between starting Id and Ending Id
i have tried it with looping but response is very slow in real world.
any body help me with query ???
This is what I have tried so far...
declare #sql varchar(8000) = '
select top '+cast((select max(id_to) from #sample) as varchar(100))+' identity(int,1,1) as guidid into tally from sysobjects,syscolumns '
exec (#sql)
alter table Tally add slab varchar(10)
create clustered index idx on Tally(guidid)
create clustered index idx on #sample(id_frm asc,id_to desc)
update Tally set slab = rowguid
from #sample join Tally on guidid between id_frm and id_to
delete from Tally where slab is null
select * from Tally
This query works fine with small numbers
But My real time table have 13 digit nos. It through Arithmetic overflow error
Assuming the range id_frm and id_to is relatively small integers, e.g. < 1M, one technique to approach this problem is to create a table with all values in the range and join to it:
WITH lotsOfNumbers AS
(
SELECT ROW_NUMBER() OVER (ORDER BY o1.object_id) AS id
FROM sys.objects o1 CROSS JOIN sys.objects o2
)
INSERT INTO #targetTable
SELECT l.ID
FROM lotsOfNumbers l
INNER JOIN #sample
ON l.ID BETWEEN #sample.id_frm AND #sample.id_to;
SqlFiddle here
A permanent table with the necessary range of ID's and a clustered index on the ID would improve performance, obviously.
Add in a DISTINCT if your ranges overlap, and you don't want duplicates in the result.
If you are able to get a full range of acceptable values into another table, you can use it without looping. The meathod below gets the minimum (1) and maximum (20), and the temporary table named #range will return everything in between.
drop table #sample
drop table #range
create table #sample (id_frm int ,id_to int)
insert into #sample values( 1,5)
insert into #sample values( 7,13)
insert into #sample values( 17,20)
create table #range (id int)
insert into #range select 1
go
insert into #range select top 1 max(id)+ 1 from #range
go 100
declare #min int
declare #max int
set #min= (select min(id_frm ) from #sample )
set #max = (select max(id_to) from #sample )
select * from #range where id between #min and #max

Inserting batch of rows into two tables in SQL Server 2008

I have a requirement to insert multiple rows into table1 and at the same time insert a row into table2 with a pkID from table1 and a value that comes from a SP parameter.
I created a stored procedure that performs a batch insert with a table valued parameter which contains the rows to be inserted into table1. But I have a problem with inserting the row into table2 with the corresponding Id (identity) from table1, along with parameter value that I have passed.
Is there anyone who implemented this, or what is the good solution for this?
CREATE PROCEDURE [dbo].[oSP_TV_Insert]
#uID int
,#IsActive int
,#Type int -- i need to insert this in table 2
,#dTableGroup table1 READONLY -- this one is a table valued
AS
DECLARE #SQL varchar(2000)
DECLARE #table1Id int
BEGIN
INSERT INTO dbo.table1
(uID
,Name
,Contact
,Address
,City
,State
,Zip
,Phone
,Active)
SELECT
#uID
,Name
,Contact
,Address
,City
,State
,Zip
,Phone
,Active
,#G_Active
FROM #dTableGroup
--the above query will perform batch insert using the records from dTableGroup which is table valued
SET #table1ID = SCOPE_IDENTITY()
-- this below will perform inserting records to table2 with every Id inserted in table1.
Insert into table2(#table1ID , #type)
You need to temporarily store the inserted identity values and then create a second INSERT statement - using the OUTPUT clause.
Something like:
-- declare table variable to hold the ID's that are being inserted
DECLARE #InsertedIDs TABLE (ID INT)
-- insert values into table1 - output the inserted ID's into #InsertedIDs
INSERT INTO dbo.table1(ID, Name, Contact, Address, City, State, Zip, Phone, Active)
OUTPUT INSERTED.ID INTO #InsertedIDs
SELECT
#ID, Name, Contact, Address, City, State, Zip, Phone, Active, #G_Active
FROM #dTableGroup
and then you can have your second INSERT statement:
INSERT INTO dbo.table2(Table1ID, Type)
SELECT ID, #type FROM #InsertedIDs
See the MSDN docs on the OUTPUT clause for more details on what you can do with the OUTPUT clause - one of the most underused and most "unknown" features of SQL Server these days!
Another approach using OUTPUT clause and only one statement for inserting data in both destination tables:
--Parameters
DECLARE #TableGroup TABLE
(
Name NVARCHAR(100) NOT NULL
,Phone VARCHAR(10) NOT NULL
);
DECLARE #Type INT;
--End Of parameters
--Destination tables
DECLARE #FirstDestinationTable TABLE
(
FirstDestinationTableID INT IDENTITY(1,1) PRIMARY KEY
,Name NVARCHAR(100) NOT NULL
,Phone VARCHAR(10) NOT NULL
);
DECLARE #SecondDestinationTable TABLE
(
SecondDestinationTable INT IDENTITY(2,2) PRIMARY KEY
,FirstDestinationTableID INT NOT NULL
,[Type] INT NOT NULL
,CHECK([Type] > 0)
);
--End of destination tables
--Test1
--initialization
INSERT #TableGroup
VALUES ('Bogdan SAHLEAN', '0721200300')
,('Ion Ionescu', '0211002003')
,('Vasile Vasilescu', '0745600800');
SET #Type = 9;
--execution
INSERT #SecondDestinationTable (FirstDestinationTableID, [Type])
SELECT FirstINS.FirstDestinationTableID, #Type
FROM
(
INSERT #FirstDestinationTable (Name, Phone)
OUTPUT inserted.FirstDestinationTableID
SELECT tg.Name, tg.Phone
FROM #TableGroup tg
) FirstINS
--check records
SELECT *
FROM #FirstDestinationTable;
SELECT *
FROM #SecondDestinationTable;
--End of test1
--Test2
--initialization
DELETE #TableGroup;
DELETE #FirstDestinationTable;
DELETE #SecondDestinationTable;
INSERT #TableGroup
VALUES ('Ion Ionescu', '0210000000')
,('Vasile Vasilescu', '0745000000');
SET #Type = 0; --Wrong value
--execution
INSERT #SecondDestinationTable (FirstDestinationTableID, [Type])
SELECT FirstINS.FirstDestinationTableID, #Type
FROM
(
INSERT #FirstDestinationTable (Name, Phone)
OUTPUT inserted.FirstDestinationTableID
SELECT tg.Name, tg.Phone
FROM #TableGroup tg
) FirstINS
--check records
DECLARE #rc1 INT, #rc2 INT;
SELECT *
FROM #FirstDestinationTable;
SET #rc1 = ##ROWCOUNT;
SELECT *
FROM #SecondDestinationTable;
SET #rc2 = ##ROWCOUNT;
RAISERROR('[Test2 results] #FirstDestinationTable: %d rows; ##SecondDestinationTable: %d rows;',1,1,#rc1,#rc2);
--End of test1
Since you need all inserted identity values, look at the output clause of the insert statement: http://msdn.microsoft.com/en-us/library/ms177564.aspx

Resources