Inserting into a primary key field in SQL Server - sql-server

Is there a way to increment an ID field that has a primary key in an INSERT INTO SELECT statement?
What I would want to do is take the last ID of the table and insert an incremented ID with each new record produced by the INSERT INTO SELECT statement?

You can do it like this:
DECLARE #lastId int = 0
SELECT #lastId = MAX(Id) From YourTable
INSERT INTO YourTable (Id, Data)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT 0))) + #lastId, at.Data
FROM AnotherTable at
Be sure to add it inside a Transaction scope.
SqlFiddle: http://www.sqlfiddle.com/#!3/d23642/5
Anyway I strongly suggest you to use an IDENTITY column to avoid collisions.

Maybe get the max id and then increse in one on each Insert
INSERT MAX(ID)+1

I think something like this is what you are looking for. Let's assume the PK is an INT for demo purposes.
--Get the last/greatest PK value in first table.
DECLARE #LastPKValue INT
SELECT #LastPKValue = MAX(PKCol)
FROM [schema].[YourTable]
INSERT INTO [schema].[YourTable] (PKCol, ColA, ColB, ColC)
SELECT
ROW_NUMBER() OVER( ORDER BY sot.[SomeColumnName]) + #LastPKValue,
OtherColumnA,
OtherColumnB,
OtherColumnC
FROM [schema].[SomeOtherTable] sot

Related

Calculating statistics of interactions between football players

I have a table of kicks between a number of football players. Most interactions have both a kicker and receiver, but sometimes the pass is made but never received. The table contains 3 columns. For purposes of the example, I have added a "PassID" column to assist with the description of the problem.
The table looks as follows:
create table #T (Player1 varchar(25),Action varchar(25),Player2 varchar(25),PassID int)
insert into #T select 'Jamie','Kicked to','Pierre',1
insert into #T select 'Pierre','Received from ','Jamie',1
insert into #T select 'Jamie','Kicked to ','Mohamed',2
insert into #T select 'Jamie','Received from ','Kun',3
insert into #T select 'Kun ','Kicked to','Jamie',3
insert into #T select 'Mohamed','Received from ','Pierre',4
insert into #T select 'Pierre','Kicked to','Mohamed',4
insert into #T select 'Mohamed','Kicked to','Kun',5
insert into #T select 'Jamie ','Kicked to ','Kun',6
insert into #T select 'Kun ','Received from ','Jamie',6
insert into #T select 'Jamie','Received from ','Kun',7
insert into #T select 'Kun ','Kicked to','Jamie',7
I have to answer the following question using SQL server:
How many unique interactions exist, where a unique interaction is defined as a kick between two players, whether completed or not and where the direction of the interaction does not matter?
In this simple example, I know the answer is 5,being:
Jamie/Pierre
Jamie/Mohamed
Jamie/Kun
Mohamed/Pierre
Mohamed/Kun
How do I extract this answer from the table using T-SQL statement?
SELECT COUNT(DISTINCT CASE
WHEN Player1 > Player2 THEN CONCAT(Player1,'+',Player2)
ELSE CONCAT(Player2,'+',Player1)
END )
FROM #T
WHERE Action = 'Kicked To';
Here is a SQL Fiddle
Try with the below code.
Select CONCAT(x.Player1,'/',x.Player2)Title from (
Select *,ROW_NUMBER() over (PARTITION by passid order by passid)Row from #T
)X
where Row=1

Filling the ID column of a table NOT using a cursor

Tables have been created and used without and ID column, but ID column is now needed. (classic)
I heard everything could be done without cursors. I just need every row to contain a different int value so I was looking for some kind of row number function :
How do I use ROW_NUMBER()?
I can't tell exactly how to use it even with these exemples.
UPDATE [TableA]
SET [id] = (select ROW_NUMBER() over (order by id) from [TableA])
Subquery returned more than 1 value.
So... yes of course it return more than one value. Then how to mix both update and row number to get that column filled ?
PS. I don't need a precise order, just unique values. I also wonder if ROW_NUMBER() is appropriate in this situation...
You can use a CTE for the update
Example
Declare #TableA table (ID int,SomeCol varchar(50))
Insert Into #TableA values
(null,'Dog')
,(null,'Cat')
,(null,'Monkey')
;with cte as (
Select *
,RN = Row_Number() over(Order by (Select null))
From #TableA
)
Update cte set ID=RN
Select * from #TableA
Updated Table
ID SomeCol
1 Dog
2 Cat
3 Monkey
You can use a subquery too as
Declare #TableA table (ID int,SomeCol varchar(50))
Insert Into #TableA values
(null,'Dog')
,(null,'Cat')
,(null,'Monkey');
UPDATE T1
SET T1.ID = T2.RN
FROM #TableA T1 JOIN
(
SELECT ROW_NUMBER()OVER(ORDER BY (SELECT 1)) RN,
*
FROM #TableA
) T2
ON T1.SomeCol = T2.SomeCol;
Select * from #TableA

How To Set Limit Table Row SQL?

How to set limit table row in SQL Server?
I want to set limit of my table rows to 100 rows only.
So when the table have more than 100 rows, I want to delete first row then add new row to last row (100).
How can I do this?
One thing that i can assure you..
Create a trigger that if > 100 then delete first record record.
see here as your guide.
I think you hv to do two things
i) Create Trigger
declare #MaxRowLimit int=5
declare #t table(col1 int)
insert into #t values(1),(2),(3),(4),(5)
insert into #t VALUES(12)
;With CTE as
(
select top (#MaxRowLimit) col1
from #t t1
order by t1.col1 desc
)
,CTE1 as(
select * from #t t
where not exists
(select col1
from cte t1 where t.col1=t1.col1
)
)
delete from cte1
select * from #t
ii) If it is bulk insert then,you hv to do manipulation before bulk insert.
like if bulk insert count is greater than 100 then sort and keep last 100 rows and remove rest rows.

How can I delete the duplicate rows while keeping the original record?

I have an one table as below a picture which indicates some duplicated rows.I can find the duplicated rows but I could not able to delete it because of there is no any unique ID that I can distinguish. There were lots of duplicated rows like that in same table I just screenshot a piece of that.
As a result,according to the below picture, how can I delete the duplicated rows but keep original ?
One solution you could consider is copying all unique records into a temporary table, thus removing the duplicates. You could then truncate the original table and re-populate it from the temporary table you've created. The code would be something like this:
SELECT DISTINCT * INTO #tempTable FROM MyTable
TRUNCATE TABLE MyTable;
INSERT INTO MyTable (LocationID, UnitID, CameraID ... IsActiveHours)
SELECT LocationID, UnitID, CameraID ... IsActiveHours FROM #tempTable;
This isn't always an option due to key constraints and amount of data, but useful in certain cases. Take it as you may.
You could use a cte and Row_Number() to accomplish this. If you are satisfied with the results, remove the final select and un-comment the delete statement
;with cte as (
Select *,RowNr=Row_Number() over (Partition By LocationId Order by Date_T)
From YourTable
)
Select * from cte Where RowNr>1
-- Delete From cte Where RowNr>1
You would be best adding an identity column to make things easier however this can be done without a TRUNCATE using the following:
--GET DUPLICATE ROWS INTO A TEMP TABLE (YOU MAY NOT NEED TO USE ALL THE COLUMNS TO IDENTIFY A DUPLICATE)
SELECT ROW_NUMBER() OVER (ORDER BY ColA) AS RowNo, ColA, ColB, ColC, COUNT(*) As [Count]
INTO #TEMP1
FROM test
GROUP BY ColA, ColB, ColC
HAVING COUNT(*) > 1
--LOOP THROUGH DUPLICATES
DECLARE #RowNo INT
DECLARE #Duplicates INT
SET #RowNo = 1
WHILE EXISTS(SELECT * FROM #TEMP1)
BEGIN
--GET A COUNT OF ADDITIONAL ROWS FOR THIS DUPLICATE
SET #Duplicates = (SELECT [Count] FROM #TEMP1 WHERE RowNo = #RowNo) - 1
--DELETE THE ROWS WE DONT NEED
DELETE TOP (#Duplicates) t1
FROM test t1
JOIN #TEMP1 t2 ON t1.ColA = t2.ColA AND t1.ColB = t2.ColB AND t1.ColC = t2.ColC
WHERE t2.RowNo = #RowNo
--REMOVE THE ROW FROM THE TEMP TABLE
DELETE FROM #TEMP1 WHERE RowNo = #RowNo
--INCREASE THE ROW NO TO MOVE TO THE NEXT ROW
SET #RowNo = #RowNo + 1
END
--DROP THE TEMP TABLE
DROP TABLE #TEMP1
This is the query that fix this issue.
WITH X AS (
SELECT ROW_NUMBER() OVER(PARTITION BY LocationId,date_t ORDER BY LocationId desc) as 'rownum',LocationId,
date_T AS T
FROM Counts
)
--SELECT * FROM X WHERE rownum >1
DELETE FROM X
WHERE rownum <> 1

T-SQL: Two Level Aggregation in Same Query

I have a query that joins a master and a detail table. Master table records are duplicated in results as expected. I get aggregation on detail table an it works fine. But I also need another aggregation on master table at the same time. But as master table is duplicated, aggregation results are duplicated too.
I want to demonstrate this situation as below;
If Object_Id('tempdb..#data') Is Not Null Drop Table #data
Create Table #data (Id int, GroupId int, Value int)
If Object_Id('tempdb..#groups') Is Not Null Drop Table #groups
Create Table #groups (Id int, Value int)
/* insert groups */
Insert #groups (Id, Value)
Values (1,100), (2,200), (3, 200)
/* insert data */
Insert #data (Id, GroupId, Value)
Values (1,1,10),
(2,1,20),
(3,2,50),
(4,2,60),
(5,2,70),
(6,3,90)
My select query is
Select Sum(data.Value) As Data_Value,
Sum(groups.Value) As Group_Value
From #data data
Inner Join #groups groups On groups.Id = data.GroupId
The result is;
Data_Value Group_Value
300 1000
Expected result is;
Data_Value Group_Value
300 500
Please note that, derived table or sub-query is not an option. Also Sum(Distinct groups.Value) is not suitable for my case.
If I am not wrong, you just want to sum value column of both table and show it in a single row. in that case you don't need to join those just select the sum as a column like :
SELECT (SELECT SUM(VALUE) AS Data_Value FROM #DATA),
(SELECT SUM(VALUE) AS Group_Value FROM #groups)
SELECT
(
Select Sum(d.Value) From #data d
WHERE EXISTS (SELECT 1 FROM #groups WHERE Id = d.GroupId )
) AS Data_Value
,(
SELECT Sum( g.Value) FROM #groups g
WHERE EXISTS (SELECT 1 FROM #data WHERE GroupId = g.Id)
) AS Group_Value
I'm not sure what you are looking for. But it seems like you want the value from one group and the collected value that represents a group in the data table.
In that case I would suggest something like this.
select Sum(t.Data_Value) as Data_Value, Sum(t.Group_Value) as Group_Value
from
(select Sum(data.Value) As Data_Value, groups.Value As Group_Value
from data
inner join groups on groups.Id = data.GroupId
group by groups.Id, groups.Value)
as t
The edit should do the trick for you.

Resources