假定 STRING_SPIT SQL 操作中的行顺序



我有一个存储过程,它需要假设行顺序始终相同才能正常运行,否则我会得到不正确的数据。 用户提供需要查询的 ID 字符串,存储过程使用 STRING_SPLIT(@Parameter,','( 操作将此字符串放入表中。

假设字符串将按照它们提供给表的顺序放入表中是否安全?我创建了一个单元测试并运行了 10000 次,每次检查表的顺序并成功。因此,我猜测做出这种假设是安全的。

.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

这是一个数据库<>小提琴。

您可以使用以下方法检索它们:

select tn.*
from #testnames tn
order by lev;

最新更新