SELECT TOP 1, 2, 3 RowId from TableWithNRows - sql-server-2005

Stupid problem and the answer may not exists (Gasp! Groan! Gnash! Teeth!)
I have a select:
SELECT * FROM SockDrawer WHERE Color = 'red'
This results in 3 rows with row ids of 33896, 35901, 37903
(A lot of other results too.)
What I want is something like this:
DECLARE #ROWID INT --- HOW DO I USE ARRAYS? I'll google but an example would help.
DECLARE #COUNT INT
DECLARE #LIMIT INT
SELECT * FROM SockDrawer WHERE Color = 'red'
--(Returns 3 rows. With 3 RowId's 33896, 35901, 33896)
SET #LIMIT = ##ROWCOUNT
SET #COUNT = 1
WHILE #COUNT < #LIMIT BEGIN
SET #ROWID[0] = (SELECT SockKey From SockDrawer WHERE RowID = 33896)
SET #ROWID[1] = (SELECT SockKey From SockDrawer WHERE RowID = 35901)
SET #ROWID[2] = (SELECT SockKey From SockDrawer WHERE RowID = 33896)
SET #Count = #Count + 1
END
GO
Then I need to:
SET #COUNT = 0
WHILE #COUNT < #LIMIT
BEGIN
DELETE FROM SockDrawer WHERE RowID = #ROWID[#COUNT]
END
GO
The trick is I'll never know if I'm dealing with 1 row to delete or 50.
I'm a dork. I can change. If I want to.

If you don't care about which sock is left for each color, then:
;WITH x AS
(
SELECT *, rn = ROW_NUMBER() OVER (PARTITION BY Color ORDER BY RowID)
FROM dbo.SockDrawer
)
DELETE x WHERE rn > 1;
If you care which one you keep, adjust the ORDER BY accordingly.

Related

SQL Server: is this a bug or do I have a misunderstanding?

Today I'm found a very sticky problem on SQL Server 2014.
Scenario: I want to pay awards to my customer (some pin code for cell phone operator)
In last cycle of loop T.Used = 0 condition is bypassed and is not working. I know in other conditions in that query (T.Cash < (#myAwards - #paid)) is there a mistake and I must to use T.Cash <= (#myAwards - #paid) instead of this but please focus on main question.
Why it's happened when I update Used flag to 1 (True) then in next loop it's selected while it doesn't have a valid condition (T.Used = 0)?
DECLARE #myAwards INT = 90000,
#paid INT = 0;
DECLARE #Temp TABLE
(
Id INT NOT NULL,
Pin VARCHAR(100) NOT NULL,
Cash INT NOT NULL,
[Weight] INT NULL,
Used BIT NOT NULL
)
INSERT INTO #Temp
SELECT
UPFI.Id, UPFI.PinCode,
PT.Cash, NULL, 0
FROM
dbo.UploadedPinFactorItem UPFI WITH (NOLOCK)
INNER JOIN
dbo.PinType PT WITH (NOLOCK) ON PT.ID = UPFI.PinTypeID
WHERE
PT.Cash <= #myAwards
UPDATE T
SET [Weight] = ISNULL((SELECT COUNT(TT.Id)
FROM #Temp TT
WHERE TT.Cash = T.Cash), 0) * T.Cash
FROM #Temp T
--For debug (first picture)
SELECT * FROM #Temp
DECLARE #i int = 1
DECLARE #count int = 0
SELECT #count = COUNT([Id]) FROM #Temp C WHERE C.Used = 0
WHILE (#i <= #count AND #paid < #myAwards)
BEGIN
DECLARE #nextId INT,
#nextCash INT,
#nextFlag BIT;
-- 'T.Used = 0' condition is by passed
SELECT TOP (1)
#nextId = T.Id, #nextCash = T.Cash, #nextFlag = T.Used
FROM
#Temp T
WHERE
T.Used = 0
AND T.Cash < (#myAwards - #paid)
ORDER BY
T.[Weight] DESC, T.Cash DESC, T.Id DESC
UPDATE #Temp
SET Used = 1
WHERE Id = #nextId
SET #i = #i + 1
SET #paid = #paid + #nextCash
--Show result in second picture
SELECT
#i AS 'i', #paid AS 'paid', #nextFlag AS 'flag', #nextId AS 'marked Id',*
FROM
#temp T
ORDER BY
T.[Weight] DESC, T.Cash DESC, T.Id DESC
END
SELECT 'final', #paid, *
FROM #temp T
ORDER BY T.[Weight] DESC, T.Cash DESC, T.Id DESC
Please let me to understand this is a bug or I have misunderstanding
First screenshot:
Second screenshot (result of loop):
Third screenshot (final result):
As per my comments:
This isn't a problem with the condition, the problem is with the implemented logic. After i = 4, there are no more rows where T.Used = 0 AND T.Cash < (#myAwards - #paid), that makes it so your reassigning variables gets zero rows, so they mantain the previous values.
You can test this behavior by doing:
DECLARE #A INT = 10;
SELECT #A = object_id
FROM sys.all_objects
WHERE name = 'an object that doesn''t exist'
SELECT #A;

Is there any way to select records if top clause parameter is null?

Is there any way to select records if top clause parameter is null?
DECLARE #count FLOAT = 0;
Select #count = count from tblDetails
SELECT TOP(#count) from tblCompany
If #count var is null than i want to select all records from tblCompany.
DECLARE #count FLOAT = 0;
Select #count = count(1) from tblDetails
IF #count > 0
BEGIN
SELECT TOP(#intRecords) * from tblCompany
END
ELSE
BEGIN
SELECT * FROM tblCompany
END
If you do not want to write the query twice - although only one will get executed, you can try this:
DECLARE #count FLOAT = 0;
Select #count = count(1) from tblDetails
IF #count = 0
BEGIN
SET #intRecords = 100000 -- Or some number larger than the possible count
END
SELECT TOP(#intRecords) * from tblCompany
When facing situations like this one, I love using SQL Rank.
In the query below I assumed you have an ID column, but you can replace it with any other column for choosing the criteria for what would be considered to be the top columns:
DECLARE #count FLOAT = 0;
Select #count = count(*) from tblDetails
SELECT * FROM
(
SELECT
RANK () OVER
( ORDER BY ID ) 'Rank', -- <-- Assuming you have an ID column, replace with any other criteria for what will be considered as top...
*
FROM tblCompany
) tmp
WHERE (#count IS NULL) OR tmp.Rank <= #count
I think this would work:
DECLARE #count AS INT ;
Set #count = (Select count(*) from tblDetails);
SELECT TOP(ISNULL(#count,5)) * from tblCompany

Getting one record at a time in a loop takes a long time. Is there a way around it?

This is what I have and it takes forever. I can't figure out a different way of doing this.
I tried cursors that is even slower. Any ideas? Thank you.
declare #i int
declare #customer_sk int
declare #numrows int
declare #iprotable TABLE (idx int Primary Key IDENTITY(1,1),customer_sk int)
INSERT #iprotable
select distinct ipro.Customer_SK from IproProfile ipro inner join vwUsageLast60Days usage on usage.Customer_SK =ipro.Customer_SK
SET #i = 1
SET #numrows = (SELECT COUNT(*) FROM #iprotable)
IF #numrows > 0
WHILE (#i <= (SELECT MAX(idx) FROM #iprotable))
BEGIN
SET #customer_sk = (SELECT customer_sk FROM #iprotable WHERE idx = #i)
update IproProfile set TopClassification=x.clas
from
(
select top 1 website web, classification clas, COUNT(classification)cnt, customer_sk cust_sk
from vwusagelast60days group by website, customer_sk, classification
having Customer_SK=#customer_sk
order by cnt desc
)x
where Customer_SK=x.cust_sk
set #i=#i+1
end

SQL Server 2000 : generating and incrementing data from column conditionally without using CURSOR

:)
Is there any way to create an index, and incrementing with a given condition, but without CURSOR handling/usage
For example:
The condition in my case is that: "if the current color (this is the item to be checked) is the same as the last one: not increment, otherwise increment in one unit"
This must be in a SQL query with no CURSOR USAGE and of course a good time (work with ... 10000 rows at least)
Thanks in advance.
EDIT: I forgot to mention that NEW_INDEX Column doesn't exist. It must be generated with the with the query.
EDIT2: Is there a way that only make use of SELECT/INSERT/UPDATE statements? (not set, declare...)
Assume a table called Colors with fields ID, Color, and ColorIndex of types int, varchar, and int respectively. I also assume the OP means prev / after based on an ordering of the ID field in asc order.
You could do this without a cursor, and use a while loop...but it definately isn't set based:
DECLARE #MyID int
DECLARE #CurrentIndex int
DECLARE #CurrentColor varchar(50)
DECLARE #PreviousColor varchar(50)
SET #CurrentIndex = (SELECT 0)
SET #MyID = (SELECT TOP 1 ID FROM Colors ORDER BY ID ASC)
SET #CurrentColor = (SELECT '')
SET #PreviousColor = (SELECT Color FROM Colors WHERE ID = #MyID)
WHILE (#MyID IS NOT NULL)
BEGIN
IF (#CurrentColor <> #PreviousColor)
BEGIN
SET #PreviousColor = (SELECT Color FROM Colors WHERE ID = #MyID)
SET #CurrentIndex = (SELECT #CurrentIndex + 1)
UPDATE Colors SET ColorIndex = #CurrentIndex WHERE ID = #MyID
END
ELSE
BEGIN
UPDATE Colors SET ColorIndex = #CurrentIndex WHERE ID = #MyID
SET #PreviousColor = (SELECT Color FROM Colors WHERE ID = #MyID)
END
SET #MyID = (SELECT TOP 1 ID FROM Colors WHERE ID > #MyID ORDER BY ID ASC)
SET #CurrentColor = (SELECT Color FROM Colors WHERE ID = #MyID)
END
The result after execution:
Performance wasn't too shabby as long as ID and color are indexed. The plus side is it is a bit faster then using a regular old CURSOR and it's not as evil. Solution supports SQL 2000, 2005, and 2008 (being that you are using SQL 2000 which did not support CTEs).
declare #ID int,
#MaxID int,
#NewIndex int,
#PrevCol varchar(50)
select #ID = min(ID),
#MaxID = max(ID),
#PrevCol = '',
#NewIndex = 0
from YourTable
while #ID <= #MaxID
begin
select #NewIndex = case when Colour = #PrevCol
then #NewIndex
else #NewIndex + 1
end,
#PrevCol = Colour
from YourTable
where ID = #ID
update YourTable
set NewIndex = #NewIndex
where ID = #ID
set #ID = #ID + 1
end
https://data.stackexchange.com/stackoverflow/q/122958/
select
IDENTITY(int,1,1) as COUNTER
,c1.ID
into
#temp
from
CUSTOMERS c1
left outer join (
select
c1.ID, max(p.ID) as PRV_ID
from
CUSTOMERS c1,
(
select
ID
from
CUSTOMERS
) p
where
c1.ID > p.ID
group by
c1.ID
) k on k.ID = c1.ID
left outer join CUSTOMERS p on p.ID = k.PRV_ID
where
((c1.FAVOURITE_COLOUR < p.FAVOURITE_COLOUR)
or
(c1.FAVOURITE_COLOUR > p.FAVOURITE_COLOUR)
or
p.FAVOURITE_COLOUR is null)
update
CUSTOMERS
set
NEW_INDEX = i.COUNTER
--select *
from
CUSTOMERS
inner join (
select
c1.ID, max(t.COUNTER) as COUNTER
from
CUSTOMERS c1,
(
select
ID
,COUNTER
from
#temp
) t
where
c1.ID >= t.ID
group by
c1.ID
) i on i.ID = CUSTOMERS.ID
drop table #temp
select * from CUSTOMERS

SQL increment a number

Problem:
I want to increment a number based on a table.
So for example, if a table contains
row
1 1 2 3 4 4 4 5
mytable column should increment based on this taking the max(row) + 1 in the above column. So the outcome should look like this:
6 6 7 8 9 9 9 10
This is the code so far:
OPEN cur
DECLARE #WORKING_ON_ID INT
FETCH NEXT FROM cur INTO #WORKING_ON_ID
WHILE ##FETCH_STATUS = 0
BEGIN
SET #MAX_ID = #MAX_ID + 1
UPDATE
#WorkingTable
SET
ID = #MAX_ID
WHERE
ID = #WORKING_ON_ID
FETCH NEXT FROM cur INTO #WORKING_ON_ID
END
CLOSE cur
DEALLOCATE cur
Could you please help me in getting a solution to this problem.
Thanks!
I think you could do it easily with this:
UPDATE your_table
SET id = id + (SELECT MAX(id) FROM your_table)
Wouldn't it be easier to just take the maximum and add it to this ID column? (Remember: the ID column can't be an identity column, otherwise an update will fail)
DECLARE #MAXID INT
SELECT #MAXID = MAX(ID) FROM #WorkingTable
UPDATE #WorkingTable SET ID = ID + #MAXID
Please Try this Code:
Declare #count int = 0
UPDATE table
SET #count = code = #count + 1
Why use a cursor? Wouldn't this solve your problem as well:
DECLARE #MAXID int
SELECT #MAXID=MAX(ID) FROM YourTable
UPDATE YourTable SET ID = ID + #MAXID
In SQL Server 2005 or later version:
WITH cte AS (
SELECT ID, MAX(ID) OVER () AS delta FROM atable
)
UPDATE cte
SET ID = ID + delta;