在SQL中的for循环在0和1的序列中查找1的位置

时间:2018-10-31 19:23:40

标签: sql sql-server sql-function sql-server-2017

下面是c#中的for循环,它按0和1的顺序返回1的位置,这是我的代码

public string OnesPosition(string statusBits)
{
     string onePos = "";
     for (int i = 0; i < statusBits.Length; i++)
         {
           if (statusBits[i] == '1')
           {
              onePos = onePos + Convert.ToSingle(i + 1) + ",";
           }
         }
    onePos = string.IsNullOrEmpty(onePos ) ? "0," : onePos ;
    return onePos;
}

var result = OnesPosition("00000000000101");

这将返回:结果= 12,14

如何在sql查询或使用SQL函数中做到这一点? 使用SQL Server Management Studio v17.9

7 个答案:

答案 0 :(得分:4)

另一个选择

示例

Declare @S varchar(50) = '00000000000101'

Select Stuff((Select concat(',',N )
                From ( 
                      Select Top (len(@S)) N=Row_Number() Over (Order By (Select NULL)) 
                       From  master..spt_values 
                      ) s 
                Where substring(@S,N,1)='1'
                Order By N
                For XML Path ('')),1,1,'')

返回

12,14

答案 1 :(得分:1)

循环在SQL Server中不能很好地发挥作用,但这是一种方法。

declare @ones varchar(16) = '00000000100101'
declare @pos int = 1
declare @result varchar(256) = ''

while @pos <= len(@ones)
begin
    set @result = @result + case when substring(@ones,@pos,1) = 1 then ',' + cast(@pos as varchar) else '' end
    set @pos = @pos + 1
end

select right(@result,len(@result) - 1)

答案 2 :(得分:1)

解决方案:

另一种可能的方法是使用递归CTE(返回每个数字和数字位置)和组连接。

使用STRING_AGG()(来自SQL Server 2017):

DECLARE @ones varchar(16)
SET @ones = '1000000001001011';

WITH Digits AS (
   SELECT 1 AS DigitPosition, SUBSTRING(@ones, 1, 1) AS Digit
   UNION ALL
   SELECT DigitPosition + 1, SUBSTRING(@ones, DigitPosition + 1, 1)
   FROM Digits
   WHERE DigitPosition < LEN(@ones)
) 
SELECT STRING_AGG(DigitPosition, ',')
FROM Digits
WHERE Digit = '1'

使用FOR XML

DECLARE @ones varchar(16)
SET @ones = '1000000001001011';

WITH Digits AS (
   SELECT 1 AS DigitPosition, SUBSTRING(@ones, 1, 1) AS Digit
   UNION ALL
   SELECT DigitPosition + 1, SUBSTRING(@ones, DigitPosition + 1, 1)
   FROM Digits
   WHERE DigitPosition < LEN(@ones)
) 
SELECT CONVERT(varchar(max), DigitPosition) + ','
FROM Digits
WHERE Digit = '1'
FOR XML PATH('')

输出:

1,10,13,15,16

答案 3 :(得分:0)

我认为使用循环不是一个好主意,但是既然您想要

DECLARE @Str VARCHAR(45) = '000001000000101',
        @OutPut VARCHAR(45) = '',
        @I INT = 1;

WHILE @I <= LEN(@Str)
BEGIN
 IF (SELECT SUBSTRING(@Str, @I, 1)) = '1'
   SET @OutPut = @OutPut + (SELECT CAST(@I AS VARCHAR(10))) + ','; 
   --Convert.ToSingle(i + 1) why +1?
 SET @I = @I + 1;
END


SELECT @OutPut;

答案 4 :(得分:0)

使用计数表和直接tsql的另一种方法:

WITH Tally(i) AS (
   SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS i
   FROM (VALUES (0), (0), (0), (0), (0), (0), (0)) a(n)
   CROSS JOIN (VALUES (0), (0), (0), (0), (0), (0)) b(n)
) 
SELECT bitloc
FROM
    (
        SELECT SUBSTRING(x.d, i, 1)  as bitset, i bitloc
        FROM (VALUES ('00000000000101')) x(d)
        CROSS JOIN Tally
    ) sub
WHERE bitset = 1

答案 5 :(得分:0)

这是基于@scsimon响应的函数,它可以正常工作。

CREATE FUNCTION [dbo].[ConvertTo1Positions]  
(  
    @ones AS varchar(16),  
    @pos AS INT = 1,
    @result varchar(256) 
) RETURNS VARCHAR(MAX) AS BEGIN  

   while @pos <= len(@ones)
begin
    set @result = @result + iif(substring(@ones,@pos,1) = 1,cast(@pos as char),'')
    set @pos = @pos + 1
end 
    RETURN @result;  

END  

答案 6 :(得分:0)

或者这个...

DECLARE @string VARCHAR(100) = '00000000000101';

WITH 
    cte_n1 (n) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (n)), 
    cte_n2 (n) AS (SELECT 1 FROM cte_n1 a CROSS JOIN cte_n1 b),
    cte_Tally (n) AS (
        SELECT TOP (LEN(@string))
            ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
        FROM
            cte_n2 a CROSS JOIN cte_n2 b
        )
SELECT 
    STRING_AGG(t.n, ',')
FROM
    cte_Tally t
WHERE 
    SUBSTRING(@string, t.n, 1) = '1';