I have a table with 1000 unique records with one of the field as ID. For testing purpose, my requirement is that To update the last 200 records ID value to the first 200 records ID in the same table. Sequence isn't mandatory.
Appreciate help on this.
Typically I charge for doing other ppls homework, don't forget to cite your source ;)
declare #example as table (
exampleid int identity(1,1) not null
, color nvarchar(255) not null
);
insert into #example (color)
select 'black' union all
select 'green' union all
select 'purple' union all
select 'indigo' union all
select 'yellow' union all
select 'pink';
select *
from #example;
declare #max int = (select max(exampleId) from #example);
declare #min int = #max - 2
;with cte as (
select top 2 color
from #example
)
update #example
set color = a.color
from cte a
where exampleid <= #max and exampleid > #min;
select *
from #example
This script should solve the issue and will cover scenarios even if the id column is not sequential.I have included the comments to help you understand the joins and the flow of the script.
declare #test table
(
ID int not null,
Txt char(1)
)
declare #counter int = 1
/*******This variable is the top n or bottom n records in question it is 200 ,
for test purpose setting it to 20
************/
declare #delta int = 20
while(#counter <= 50)
begin
Insert into #test values(#counter * 5,CHAR(#counter+65))
set #counter = #counter + 1
end
/************Tag the records with a row id as we do not know if ID's are sequential or random ************/
Select ROW_NUMBER() over (order by ID) rownum,* into #tmp from #test
/************Logic to update the data ************/
/*Here we first do a self join on the tmp table with first 20 to last 20
then create another join to the test table based on the ID of the first 20
*/
update t
set t.ID = tid.lastID
--Select t.ID , tid.lastID
from #test t inner join
(
Select f20.rownum as first20 ,l20.rownum as last20,f20.ID as firstID, l20.ID lastID
from #tmp f20
inner join #tmp l20 on (f20.rownum + #delta) = l20.rownum
)tid on tid.firstID = t.ID and tid.first20 < = #delta
Select * from #test
drop table #tmp
Related
I have a table [Order] that has records with sequential ID (in odd number only, i.e. 1,3,5,7...989, 991, 993, 995, 997, 999), it is seen that a few records were accidentally deleted and should be inserted back, first thing is to find out what records are missing in the current table, there are hundreds of records in this table
Don't know how to write the query, can anyone kindly help, please?
I am thinking if I have to write a stored procedure or function but would be better if I can avoid them for environment reasons.
Below peuso code is what I am thinking:
set #MaxValue = Max(numberfield)
set #TestValue = 1
open cursor on recordset ordered by numberfield
foreach numberfield
while (numberfield != #testvalue) and (#testvalue < #MaxValue) then
Insert #testvalue into #temp table
set #testvalue = #textvalue + 2
Next
Next
UPDATE:
Expected result:
Order ID = 7 should be picked up as the only missing record.
Update 2:
If I use
WHERE
o.id IS NULL;
It returns nothing:
Since I didn't get a response from you, in the comments, I've altered the script for you to fill in accordingly:
declare #id int
declare #maxid int
set #id = 1
select #maxid = max([Your ID Column Name]) from [Your Table Name]
declare #IDseq table (id int)
while #id < #maxid --whatever you max is
begin
insert into #IDseq values(#id)
set #id = #id + 1
end
select
s.id
from #IDseq s
left join [Your Table Name] t on s.id = t.[Your ID Column Name]
where t.[Your ID Column Name] is null
Where you see [Your ID Column Name], replace everything with your column name and the same goes for [Your Table Name].
I'm sure this will give you the results you seek.
We can try joining to a number table, which contains all the odd numbers which you might expect to appear in your own table.
DECLARE #start int = 1
DECLARE #end int = 1000
WITH cte AS (
SELECT #start num
UNION ALL
SELECT num + 2 FROM cte WHERE num < #end
)
SELECT num
FROM cte t
LEFT JOIN [Order] o
ON t.num = o.numberfield
WHERE
o.numberfield IS NULL;
Here is the trigger
CREATE TRIGGER [dbo].[Teacher]
ON [dbo].[Teacher]
After INSERT
AS
Declare #fid int, #PR NVARCHAR(MAX),#Mycounter as INT
Select top 1 #fid = eid from human where TypeID = 2
order by NewID()
Select top 1 #PR = Pid from [dbo].[Program] Where Depid = 1
order by NewID()
Set #Mycounter =1
While #Mycounter <5
BEGIN
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID, #fid,#PR,NULL,null from INSERTED
Where eid in (Select eid from human where TypeID = 3)
set #MyCounter = #MyCounter + 1;
END
I need to insert 1000's of rows in HeadofDep table when any row is inserted in Teacher table. I have done by applying looping but all rows that get inserted in HeadofDep table have same #PR. Need it different against each row.
Also need sessionid incremented.
How can I achieve that?
Just, increment the SessionID then and put the other stuff in the loop:
Declare #fid int, #PR NVARCHAR(MAX),#Mycounter as INT
Set #Mycounter =1
While #Mycounter <5
BEGIN
Select top 1 #fid = eid from human where TypeID = 2
order by NewID()
Select top 1 #PR = Pid from [dbo].[Program] Where Depid = 1
order by NewID()
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID, #fid,#PR,NULL,null from INSERTED
Where eid in (Select eid from human where TypeID = 3)
set #MyCounter = #MyCounter + 1;
END
Also, doing such LOOPs in triggers is bad.In this case, you can change 1000 inserts with one like this:
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID + N, #fid,#PR,NULL,null
from INSERTED
CROSS APPLY
(
SELECT TOP (1000) -1+row_number() over(order by t1.number) as N
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) DS
Where eid in (Select eid from human where TypeID = 3)
I have a temp table with 3 columns "ID","Cost", "MaxCost"..below is my select statement which selects rows given particular ID..
SELECT
t.Cost
t.MaxCost
FROM #temp t
WHERE t.ID = #ID
How do i modify the above query so that even if given ID doesn't exists it still output rows with Cost = 0 & MaxCost = 0
Select both the actual and the default record, and select the first one ordering by their weight.
select top (1)
Cost,
MaxCost
from (
SELECT
t.Cost
t.MaxCost,
1 as takeme
FROM #temp t
WHERE t.ID = #ID
union all
select 0, 0, 0
) foo
order by
foo.takeme desc
declare #table table (cost int);
insert into #table values (2), (2), (3);
declare #findCost int = 1;
select * from #table where cost = #findCost
union all
select 0 as cost from #table where cost = #findCost having count(*) = 0;
set #findCost = 2;
select * from #table where cost = #findCost
union all
select 0 as cost from #table where cost = #findCost having count(*) = 0;
I have a query which results in two or more rows (just one column) and I want to catch the first row value into first temp variable and second row value into second temp variable without using multiple times the select top 1 and select top 1 order by desc
Something like this;
Select row1 value into #tempvariable1, row2 value into #tempvariable2 from blah blah
You need somehow to identify the row (I am using a row ID in the example below, ordering by value - you can order by id or something else):
DECLARE #DataSource TABLE
(
[value] VARCHAR(12)
);
INSERT INTO #DataSource
VALUES ('value 1')
,('value 2')
,('value 3');
DECLARE #tempVariable1 VARCHAR(12)
,#tempVariable2 VARCHAR(12);
WITH DataSource ([value], [rowID]) AS
(
SELECT [value]
,ROW_NUMBER() OVER (ORDER BY [value])
FROM #DataSource
)
SELECT #tempVariable1 = IIF([rowID] = 1, [value], #tempVariable1)
,#tempVariable2 = IIF([rowID] = 2, [value], #tempVariable2)
FROM DataSource;
SELECT #tempVariable1
,#tempVariable2;
You can use a CTE where you will get the X values you need and then select from it:
declare #data table(id int);
insert into #data(id) values(8), (6), (4), (3);
with vals(id, n) as (
Select top(2) id, ROW_NUMBER() over(order by id)
From #data
)
Select #A = (Select id From vals Where n = 1)
, #B = (Select id From vals Where n = 2)
You could also use PIVOT:
Select #A = [1], #B = [2]
From (
Select id, ROW_NUMBER() over(order by id)
From #data
) v(id, n)
PIVOT (
max(id) FOR n in ([1], [2])
) as piv
You have two options
Let's say we test case is build as below
create table dbo.Test
(
value varchar(100) not null
)
GO
insert into dbo.Test
values
('A'),('B'),('NO THIS ONE'),('NO THIS ONE'),('NO THIS ONE')
GO
Now let's say you fetch your data as below
select t.value
from dbo.Test t
where t.value != 'NO THIS ONE'
GO
The first and easier option is to save the data in a temp table
declare #results as Table (value varchar(100))
insert into #results
select t.value
from dbo.Test t
where t.value != 'NO THIS ONE'
you still use TOP 1 BUT not in the entire data, only in the results.
Use TOP 1 to find the first result and a second TOP 1 where value is different from the first.
declare #A varchar(100), #B varchar(100)
set #A = (select top 1 r.value from #results r)
set #B = (select top 1 r.value from #results r where r.value != #A)
select #A, #B
GO
This approach have the advantage of performance.
Of course that don't work great if both values are equal. You can fix it by using a top 1 and ordering in the inverse order.
There's a better alternative using rownumber.
It works because if you set a variable when returning multiple rows the varible sticks with the last one (in fact it's reseted for each row iteration).
The case statement makes sure the variable #A is seted only on the first row iteration.
declare #A varchar(100), #B varchar(100)
/* This way #B receives the last value and #A the first */
select #B = t.value,
#A = (case when ROW_NUMBER() OVER(order by t.Value) = 1
then t.Value else #A
end)
from dbo.Test t
where t.value != 'NO THIS ONE'
select #A, #B
I would like to perform a simple break out by quantity in SQL.
I have as follows:
Table name : Products
product quantity
======= ========
Car 2
Bike 1
Results:
Car
Car
Bike
Thanks!
One solution is to join to a table of numbers. This can repeat the row quantity times. In T-SQL, a list of numbers can be generated with a recursive CTE:
; with Numbers as
(
select max(quantity) as nr
from YourTable
union all
select nr - 1
from Numbers
where nr > 1
)
select yt.product
from YourTable yt
join Numbers nr
on nr.nr <= yt.quantity
option (maxrecursion 0)
Live example at SQL Fiddle.
Here is a non-CTE answer to show why you should use the CTE :)
MAIN TABLE
DECLARE #table TABLE
(
ID INT IDENTITY,
Product VARCHAR(20),
Quantity INT
)
OUT TABLE
DECLARE #outtable TABLE
(
ID INT IDENTITY,
Product VARCHAR(20)
)
TEST DATA
INSERT INTO #table
(
Product,
Quantity
)
SELECT 'Car',
2
UNION ALL
SELECT 'Bike',
1
Main Query
DECLARE #counter INT,
#maxcounter INT,
#curproduct INT
SELECT TOP 1
#curproduct = id
FROM #table
WHILE EXISTS ( SELECT TOP 1
1
FROM #table
WHERE ID >= #curproduct )
BEGIN
SELECT #counter = 1,
#maxcounter = quantity
FROM #table
WHERE ID = #curproduct
WHILE #counter <= #maxcounter
BEGIN
INSERT INTO #outtable
(
Product
)
SELECT product
FROM #table
WHERE id = #curproduct
SET #counter = #counter + 1
END
SET #curproduct = #curproduct + 1
END
FINALLY
SELECT *
FROM #outtable