假设 STRING_SPIT SQL 操作中的行顺序
Assuming Row order in a STRING_SPIT SQL Operation
我有一个存储过程需要假设行顺序始终相同,以便正确 运行 否则我会得到不正确的数据。用户提供需要查询的 ID 字符串,存储过程使用 STRING_SPLIT(@Parameter, ',') 操作将此字符串放入 table 中。
可以安全地假设字符串将按照它们被赋予 table 的顺序放入 table 中吗?我创建了一个单元测试 运行 10000 次,每次检查 table 的顺序并通过。因此,我猜测做出这个假设是安全的。
SQL:
CREATE PROCEDURE [dbo].[sp_TestOrder] @TestIDs varchar(5000)
AS
IF(OBJECT_ID('tempdb..#TestNames') IS NOT NULL) BEGIN DROP TABLE #TestNames END
-- INTO #FundNames
SELECT RTRIM(LTRIM(value)) AS TestIDs
INTO #TestNames
FROM string_split(@TestIDs, ',');
ALTER TABLE #TestNames ADD RowNumber INT IDENTITY(1,1)
SELECT * FROM #TestNames
IF(OBJECT_ID('tempdb..#TestNames') IS NOT NULL) BEGIN DROP TABLE #TestNames END
GO
C# 中的单元测试
[TestMethod]
public void SQLOrderTest()
{
// Arrange
string testIds = "3, 5, 1, 10";
string spName = "[dbo].[sp_TestOrder]";
string ServerName = PARR_DBDataObject.ServerName;
string DBName = PARR_DBDataObject.DBName;
// Act
bool results = true;
for(int i = 0; i < 10000; i++)
{
DataTable dt = SQL.QueryStoredProcedure(spName, DBName, ServerName, false, 5000,
new Tuple<string, object>("@TestIDs", testIds));
// First Row
if (GetRowNumber(dt, "3") != 1) results = false;
// Second Row
if (GetRowNumber(dt, "5") != 2) results = false;
// Third Row
if (GetRowNumber(dt, "1") != 3) results = false;
// Forth Row
if (GetRowNumber(dt, "10") != 4) results = false;
}
Assert.AreEqual(results, true);
}
private int GetRowNumber(DataTable dt, string TestIDValue)
{
var row = from r in dt.AsEnumerable()
where r.Field<string>("TestIDs") == TestIDValue
select new
{
TestID = r.Field<string>("TestIDs"),
rowNum = r.Field<Int32>("RowNumber")
};
return row.First().rowNum;
}
SQL 表表示 无序 集合。除非您使用 ORDER BY
,否则假设数据按特定顺序排列永远不是一个好主意。通常,单个页面上的小型数据集甚至会按照您的预期一致地排序。但是使用被记录为不正确的功能仍然是危险的。
如果你想保证排序,那么你可以插入带有order by
的记录和一个排序值。这是使用递归 CTE 的方法:
with cte as (
select convert(varchar(max), left(@testids, charindex(',', @testids + ',') - 1)) as id,
convert(varchar(max), stuff(@testids, 1, charindex(',', @testids + ','), '')) as rest,
1 as lev
union all
select convert(varchar(max), left(rest, charindex(',', rest + ',') - 1)) as id,
convert(varchar(max), stuff(rest, 1, charindex(',', rest + ','), '')),
lev + 1 as lev
from cte
where rest <> ''
)
select trim(id) as id, lev
into #testnames
from cte
where trim(id) <> ''
order by lev; -- not really needed but handy if you have an identity column
Here 是一个 db<>fiddle.
您可以使用以下方式检索它们:
select tn.*
from #testnames tn
order by lev;
我有一个存储过程需要假设行顺序始终相同,以便正确 运行 否则我会得到不正确的数据。用户提供需要查询的 ID 字符串,存储过程使用 STRING_SPLIT(@Parameter, ',') 操作将此字符串放入 table 中。
可以安全地假设字符串将按照它们被赋予 table 的顺序放入 table 中吗?我创建了一个单元测试 运行 10000 次,每次检查 table 的顺序并通过。因此,我猜测做出这个假设是安全的。
SQL:
CREATE PROCEDURE [dbo].[sp_TestOrder] @TestIDs varchar(5000)
AS
IF(OBJECT_ID('tempdb..#TestNames') IS NOT NULL) BEGIN DROP TABLE #TestNames END
-- INTO #FundNames
SELECT RTRIM(LTRIM(value)) AS TestIDs
INTO #TestNames
FROM string_split(@TestIDs, ',');
ALTER TABLE #TestNames ADD RowNumber INT IDENTITY(1,1)
SELECT * FROM #TestNames
IF(OBJECT_ID('tempdb..#TestNames') IS NOT NULL) BEGIN DROP TABLE #TestNames END
GO
C# 中的单元测试
[TestMethod]
public void SQLOrderTest()
{
// Arrange
string testIds = "3, 5, 1, 10";
string spName = "[dbo].[sp_TestOrder]";
string ServerName = PARR_DBDataObject.ServerName;
string DBName = PARR_DBDataObject.DBName;
// Act
bool results = true;
for(int i = 0; i < 10000; i++)
{
DataTable dt = SQL.QueryStoredProcedure(spName, DBName, ServerName, false, 5000,
new Tuple<string, object>("@TestIDs", testIds));
// First Row
if (GetRowNumber(dt, "3") != 1) results = false;
// Second Row
if (GetRowNumber(dt, "5") != 2) results = false;
// Third Row
if (GetRowNumber(dt, "1") != 3) results = false;
// Forth Row
if (GetRowNumber(dt, "10") != 4) results = false;
}
Assert.AreEqual(results, true);
}
private int GetRowNumber(DataTable dt, string TestIDValue)
{
var row = from r in dt.AsEnumerable()
where r.Field<string>("TestIDs") == TestIDValue
select new
{
TestID = r.Field<string>("TestIDs"),
rowNum = r.Field<Int32>("RowNumber")
};
return row.First().rowNum;
}
SQL 表表示 无序 集合。除非您使用 ORDER BY
,否则假设数据按特定顺序排列永远不是一个好主意。通常,单个页面上的小型数据集甚至会按照您的预期一致地排序。但是使用被记录为不正确的功能仍然是危险的。
如果你想保证排序,那么你可以插入带有order by
的记录和一个排序值。这是使用递归 CTE 的方法:
with cte as (
select convert(varchar(max), left(@testids, charindex(',', @testids + ',') - 1)) as id,
convert(varchar(max), stuff(@testids, 1, charindex(',', @testids + ','), '')) as rest,
1 as lev
union all
select convert(varchar(max), left(rest, charindex(',', rest + ',') - 1)) as id,
convert(varchar(max), stuff(rest, 1, charindex(',', rest + ','), '')),
lev + 1 as lev
from cte
where rest <> ''
)
select trim(id) as id, lev
into #testnames
from cte
where trim(id) <> ''
order by lev; -- not really needed but handy if you have an identity column
Here 是一个 db<>fiddle.
您可以使用以下方式检索它们:
select tn.*
from #testnames tn
order by lev;