SQL 2000 Row numbering with GROUP BY - sql-server-2000

This is my Table
################################
# id_formfield # ID # int_Sort #
################################
# 1 # 1 # 2 #
# 2 # 1 # 3 #
# 3 # 1 # 4 #
# 4 # 1 # 4 #
# 5 # 1 # 4 #
# 6 # 2 # 1 #
# 7 # 2 # 3 #
# 8 # 2 # 3 #
# 9 # 2 # 4 #
As you can see my int_sort column is messed up somehow with equal numbers and I wanna to make it sequence with row number and reset row number when ID changes.
this should be result:
############################################
# id_formfield # ID # int_Sort # rownumber #
############################################
# 1 # 1 # 2 # 1 #
# 2 # 1 # 3 # 2 #
# 3 # 1 # 4 # 3 #
# 4 # 1 # 4 # 4 #
# 5 # 1 # 4 # 5 #
# 6 # 2 # 1 # 1 #
# 7 # 2 # 3 # 2 #
# 8 # 2 # 3 # 3 #
# 9 # 2 # 4 # 4 #
Edit : id_formfield is my primary key and order by int_sort ascending

Following script should get you started. In a nutshell, the script
creates a temp table, adding an IDENTITY column to serve as rownumber
inserts your original data into the temp table
uses MIN(Rownumber) for each ID to get an offset.
JOIN the temp table with the calculated offsets to restart the count for each group.
SQL Statement
CREATE TABLE #TempTable (Rownumber INTEGER IDENTITY(1, 1), ID INTEGER)
SET IDENTITY_INSERT #TempTable OFF
INSERT INTO #TempTable
SELECT *
FROM YourOriginalTable
ORDER BY ID, int_Sort
SELECT t.ID, t.Rownumber, t.Rownumber - o.Offset
FROM #TempTable t
INNER JOIN (
SELECT ID, MIN(Rownumber) - 1 AS Offset
FROM #TempTable
GROUP BY ID
) o ON o.ID = t.ID
DROP TABLE #TempTable
Test script
DECLARE #YourTable TABLE (ID VARCHAR(1))
CREATE TABLE #TempTable (Rownumber INTEGER IDENTITY(1, 1), ID INTEGER)
SET IDENTITY_INSERT #TempTable OFF
INSERT INTO #YourTable (ID) VALUES (1)
INSERT INTO #YourTable (ID) VALUES (1)
INSERT INTO #YourTable (ID) VALUES (1)
INSERT INTO #YourTable (ID) VALUES (1)
INSERT INTO #YourTable (ID) VALUES (1)
INSERT INTO #YourTable (ID) VALUES (2)
INSERT INTO #YourTable (ID) VALUES (2)
INSERT INTO #YourTable (ID) VALUES (2)
INSERT INTO #YourTable (ID) VALUES (2)
INSERT INTO #TempTable
SELECT *
FROM #YourTable
ORDER BY ID
SELECT t.ID, t.Rownumber, t.Rownumber - o.Offset
FROM #TempTable t
INNER JOIN (
SELECT ID, MIN(Rownumber) - 1 AS Offset
FROM #TempTable
GROUP BY ID
) o ON o.ID = t.ID
DROP TABLE #TempTable

I assume you have a primary key in your table that is called PK and that you want to update the column int_sort.
select cast(PK as int) as PK,
ID,
identity(int, 1, 1) as rownumber
into #T
from YourTable
order by ID, int_sort
update YourTable
set int_sort = T.rownumber - T2.rownumber + 1
from #T as T
inner join (
select ID, min(rownumber) as rownumber
from #T
group by ID
) as T2
on T.ID = T2.ID
where T.PK = YourTable.PK
drop table #T

I have assumed that your Primary Key column is named idpk. You can obtain the desired row numbers using the following query:
SELECT ts.id, ts.int_sort,
(SELECT count(*) FROM tosort
WHERE id = ts.id AND int_sort <= ts.int_sort
AND idpk <= ts.idpk) AS row_number
FROM tosort AS ts
ORDER BY ts.id, ts.int_sort, ts.idpk;
I have created a sample case on SQL Fiddle, though only 2008 R2 is available there.
I hope this will work on SQL Server 2000.

Related

How to get First not zero value in table column in SQL Server

I have a sample table below. From that table #A I need the as shown below. Basically I wanted to get the data from first not zero row. If after that any zero occurs no issue on that.
CREATE TABLE #A
(
[Data] int
)
INSERT INTO #A
VALUES (0), (0), (0), (0), (0),
(23), (524), (723), (0), (89),
(23), (4), (51), (0), (0)
SELECT * FROM #A
Required output :
Data
-------
23
524
723
0
89
23
4
51
0
0
I tried below script but my data column itself getting sorted. Which is not working properly.
SELECT *
FROM
(SELECT
*,
ROW_NUMBER() OVER (ORDER BY data) Rn
FROM
#A) t
As #Larnu mentioned: Without a proper sequence, there is NO GTD of the desired order.
Take a peek at Unordered results in SQL
Notice I added an ID which could be an IDENTITY or even a datetime stamp
Example
Create table #A
(
id int,[Data] int
)
insert into #A values(1,0),
(2,0),
(3,0),
(4,0),
(5,0),
(6,23),
(7,524),
(8,723),
(9,0),
(10,89),
(11,23),
(12,4),
(13,51),
(14,0),
(15,0)
Option 1:
Select *
From #A
Where ID>= (Select top 1 id From #A where data<>0 Order By ID )
Order by ID
Option 2:
Select id
,data
From (
Select *
,Flg = sum(case when Data<>0 then 1 else 0 end) over (order by id)
from #A
) A
Where Flg>0
Order By ID
Results
id data
6 23
7 524
8 723
9 0
10 89
11 23
12 4
13 51
14 0
15 0

Adding Random Id for each unique value in table

I have the table like
ID RANDOM_ID
1 123
10 456
25 789
1 1112
55 1314
10 1516
I want the result to be like :
ID RANDOM_ID
1 123
10 456
25 789
1 123
55 1314
10 456
The same ID should have same random_ids. I'm using the update statement to generate the Random_IDs after creating the table.
CREATE TABLE [RANDOMID_TABLE]([ID] [int] NULL, [RANDOM_ID] [int] NULL)
GO
INSERT INTO [RANDOMID_TABLE] ([ID])
select distinct ABC_ID from RANDOMID_ABC
GO
******** This is the update statement for the RANDOM_ID column in
[RANDOMID_TABLE] table ************
UPDATE [RANDOMID_TABLE]
SET RANDOM_ID = abs(checksum(NewId()) % 1000000)
Is there something else that I need to add to the update statement?
Please advise.
Why would you use update for this? Just generate the values when you insert them:
insert into [RANDOMID_TABLE] (ID, RANDOM_ID)
select ABC_ID, abs(checksum(NewId()) % 1000000)
from RANDOMID_ABC
group by ABC_ID;
EDIT:
If your problem is collisions, then fix how you do the assignment. Just assign a number . . . randomly:
insert into [RANDOMID_TABLE] (ID, RANDOM_ID)
select ABC_ID, row_number() over (order by newid())
from RANDOMID_ABC
group by ABC_ID;
This is guaranteed to not return duplicates.
At a total guess, are you simpling wanting to UPDATE the table so that all the values of a specific ID to have the same value for Random_ID? Like this?
CREATE TABLE YourTable (ID int, Random_ID int);
INSERT INTO YourTable
VALUES(1 ,123),
(10,456),
(25,789),
(1 ,1112),
(55,1314),
(10,1516);
GO
WITH CTE AS(
SELECT ID,
Random_ID,
MIN(Random_ID) OVER (PARTITION BY ID) AS Min_Random_ID
FROM YourTable)
UPDATE CTE
SET Random_ID = Min_Random_ID;
GO
SELECT *
FROM YourTable;
GO
DROP TABLE YourTable;
Here is the script you need with use of temporary table (you need it to persist your random results for each unique ID):
DECLARE #Tbl TABLE (ID INT, RANDOM_ID INT)
INSERT #Tbl (Id) VALUES(1), (10), (25), (1), (55), (10)
SELECT Id, abs(checksum(NewId()) % 1000000) AS Random_Id INTO #distinctData FROM #Tbl GROUP BY Id
SELECT D.* FROM #Tbl T JOIN #distinctData D ON D.ID = T.ID
DROP TABLE #distinctData
Obviously, you don't need the first two rows where I create and initialize data table
Result:
Id Random_Id
1 354317
1 62026
10 532304
10 604768
25 874209
55 718643
You want one random value per ID. So one should think that the following would work:
with ids as
(
select distinct id
from randomid_table
)
, ids_with_rnd as
(
select id, abs(checksum(NewId()) % 1000000) as rnd
from ids
)
update randomid_table
set random_id =
(
select rnd
from ids_with_rnd
where ids_with_rnd.id = randomid_table.id
);
It doesn't however. SQL Server is somewhat buggy here and still creates different numbers for the same ID.
So, your best bet may be: do your update that does create different values (your original update statement). Then correct the data as follows:
update randomid_table
set random_id =
(
select min(random_id)
from randomid_table rt2
where rt2.id = randomid_table.id
);
Demo: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=504236db66fba0f12dc7e407a51451f8

SQL Server using the REPLACE function to replace values in a column spanning multiple rows

I have a table like this:
Rule | Mask |Replacement
---------------------------------
# # 12 | # |[^0-9]
# # 12 | # |[0-9]
That I constructed joining these two tables
Table 1
Mask_ID | Mask |Replacement
---------------------------------
1 | # |[^0-9]
2 | # |[0-9]
Table 2
Rule_ID | Rule
--------------
1 | # # 12
The result I want is this:
Rule | Expression
--------------------
# # 12 | [^0-9] [0-9] 12
I've been trying to use the REPLACE button to do this, but I've only been able to generate this result
Rule | Expression
--------------------
# # 12 | [^0-9] # 12
# # 12 | # [0-9] 12
I'm not sure how to get the REPLACE function to apply multiple rows to a single row. If anyone has any suggestions, I would appreciate it.
This is what I have so far, but its causing me to get the result I mentioned above:
SELECT
A.PointMask_CODE
,B.PointMasking_Rule_CODE
,B.Mask
,B.Escape_Character
,B.EscapedMaskRule
,REPLACE(A.PointMask_CODE, B.Mask, B.EscapedMaskRule)
FROM
tblStatusPointMasks_CORE A
LEFT JOIN
vwAORs_Status_PointMasks_EscapedRules B
ON
PointMask_CODE LIKE '%' + B.EscapedMask + '%' ESCAPE ISNULL(B.Escape_Character, '\')
For your given sample data, you could use a recursive common table expression (cte).
create table masks (mask_id int, mask varchar(32), replacement varchar(32));
insert into masks values
(1, '#', '[^0-9]')
,(2, '#', '[0-9]');
create table rules (rule_id int, rule_txt varchar(32));
insert into rules values
(1, '# # 12');
with cte as (
select
r.rule_id
, r.rule_txt
, masks = 0
from rules r
union all
select
r.rule_id
, rule_txt = convert(varchar(32),replace(r.rule_txt,m.mask,m.replacement))
, masks = r.masks+1
from masks m
inner join cte r
on r.rule_txt like '%'+m.mask+'%'
)
select top 1 *
from cte
order by masks desc
rextester demo: http://rextester.com/KAV58392
returns:
+---------+-----------------+-------+
| rule_id | rule_txt | masks |
+---------+-----------------+-------+
| 1 | [^0-9] [0-9] 12 | 2 |
+---------+-----------------+-------+
One more option, using string operations...
create table masks (mask_id int, mask varchar(32), replacement varchar(32));
insert into masks values
(1, '#', '[^0-9]')
,(2, '#', '[0-9]');
create table rules (rule_id int, rule_txt varchar(32));
insert into rules values
(1, '# # # # 12');
declare #Table Table (charval varchar(10))
declare #char varchar(10), #rule_txt varchar(50)
select #rule_txt=rule_txt FROM rules
while charindex(' ',#rule_txt)>0
begin
select #char=substring(#rule_txt,1,charindex(' ',#rule_txt)-1)
FROM rules
insert into #Table values (#char)
SET #rule_txt=RIGHT(#rule_txt,(len(#rule_txt)-charindex(' ',#rule_txt)))
END
insert into #Table values (#rule_txt)
select stuff((SELECT ' '+isnull(replacement,charval)
from #Table T left join masks M on M.mask=T.charval
for xml path('')),1,1,'')
drop table rules
drop table masks

How to generate AUTOMATIC Number in Teradata SQL

I want to generate AUTOMATIC Number to use TD SQL, for example as follows,
CREATE MULTISET TABLE TEST_TABLE
(
AUTO_NUMBER INT,
NAME VARCHAR(10)
)
PRIMARY INDEX (AUTO_NUMBER);
INSERT INTO TEST_TABLE
VALUES('TOM');
INSERT INTO TEST_TABLE
VALUES('JIM');
INSERT INTO TEST_TABLE
VALUES('JAN');
SELECT * FROM TEST_TABLE;
The result above will be ,
1 TOM
2 JIM
3 JAN
Create a column with the below syntax:
SEQ_NUM decimal(10,0) NOT NULL GENERATED ALWAYS AS IDENTITY
(START WITH 1
INCREMENT BY 1
MINVALUE 1
MAXVALUE 2147483647
NO CYCLE)
Usually there is a column in the table which is unique.
You can use below technique to add a column in your result set if you dont want to add extra column to your table.
select RANK() OVER ( ORDER BY ),T.* SEQ from TABLE T;
It will give you output like:
1 a xx yy
2 b xx yy
3 c xx yy

Insert multiple rows into SQL Server

I have two tables
Product (product_id, productName)
ProductSerialNumber (ProductSerialNumber_id, product_id, serialNumber, status)
I have serial numbers 12345679000 to 123456790100 (quantity: 90) for product : MILK
Is there way to do this without using multiple inserts ie
$Sn = 12345679000;
while ($Sn <= 123456790100 )
{
INSERT INTO ProductSerialNumber VALUES(...,...,$Sn,...)
$Sn++;
}
You can do this:
WITH Temp
AS
(
SELECT n
FROM(VALUES(0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) AS Temp(n)
), nums
AS
(
SELECT id = t1.n * 10 + t2.n + 1
FROM temp AS T1
CROSS JOIN temp AS t2
)
INSERT INTO ProductSerialNumber(serialnumber)
SELECT 12345679000 + id AS Serialnumber -- You can insert into other columns too
FROM nums;
SQL Fiddle Demo.
Note that: This syntax FROM(VALUES(0), (1), ..., (9)) AS Temp(n) is new to SQL Server-2008, for old versions you can use SELECT ... UNION ALL SELECT ... instead.
However, if possible, you can alter this table and make this column SerialNumber an IDENTITY(12345679000, 1) and it will be auto incremental.
Update 1
For SQL Server 2005, try this:
WITH Temp
AS
(
SELECT 1 AS id
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
), nums
AS
(
SELECT ROW_NUMBER() OVER(ORDER BY t1.id) AS id
FROM temp t1, temp t2, temp t3, temp t4
)
INSERT INTO ProductSerialNumber(serialnumber)
SELECT 12345679000 + id AS Serialnumber
FROM nums
WHERE id <= 100;
Updated SQL Fiddle Demo.
Update 2
*How does this query work? *
Firstly, I define a virtual table with only four values:
SELECT 1 AS id
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
I defined it inside a Common table expression(CTE), to reuse it later.
Then in the following CTE, I used:
FROM temp t1, temp t2, temp t3, temp t4
This will join the table temp four times with it self, therefore it will give you: 44 = 256 rows. Then I used the ranking function ROW_NUMBER() as a work a round to generate a sequence number of number from 1 to 265.
The last thing is the syntax of INSERT INTO ... SELECT ... to select the numbers <= 100 of the numbers that we already generated from the previous step and inserting them to the table.
Hope this makes sense.
here another method to insert multiple rows with procedure
CREATE PROCEDURE autoInsert
#SerialNumberStart bigint,
#SerialNumberEnd bigint,
#status int,
#productID int
AS
while #SerialNumberStart <= #SerialNumberEnd
begin
BEGIN TRAN
INSERT INTO ProductSerialNumber VALUES(#SerialNumberStart)
--print #SerialNumberStart
COMMIT TRAN;
set #SerialNumberStart=#SerialNumberStart+ 1
end