如何在SQL select上执行布尔加法

时间:2015-06-08 18:16:44

标签: sql sql-server select sum boolean

我在名为timeSchedule的数据库表列中有以下数据

00100110
00010100
00110000
00110011

布尔加法将导致

00110111

有没有办法在sql中执行此操作?像myTable

中选择sumboolean(timeSchedule)的东西

有人要求DDL + DML ..这是一个例子:

CREATE TABLE [dbo].[myTable](
    [musPracticeID] [int] IDENTITY(1,1) NOT NULL,
    [chosenDate] [datetime] NULL,
    [timeSchedule] [nvarchar](50) NULL CONSTRAINT [DF_myTable_schedule]  DEFAULT (N'0000000000000000')
)

INSERT INTO myTable (chosenDate, timeSchedule)
      VALUES (’06/07/2015’, ’01000100’);

4 个答案:

答案 0 :(得分:4)

好的,现在我们有了DDL(遗憾的是没有DML但只有一行)。我们可以提供解决方案: - )

首先!我强烈建议不要使用上面的解决方案,没有需要循环即使你不使用固定数据长度我们知道最大len(50)。

其次!如果你要解析文本,那么你应该使用SQLCLR而不是使用T-SQL进行循环和解析,在大多数情况下也是如此。

第三:-)这里是简单解决方案的简单示例。我只使用前10个字符...你可以继续50 ...你可以使用动态查询来创建查询,如果你不想自己手动编写(还有其他解决方案,我建议检查执行计划和IO用于为u)选择最佳解决方案:

CREATE TABLE [dbo].[myTable](
    [musPracticeID] [int] IDENTITY(1,1) NOT NULL,
    [chosenDate] [datetime] NULL,
    [timeSchedule] [nvarchar](50) NULL CONSTRAINT [DF_myTable_schedule]  DEFAULT (N'0000000000000000')
)
GO
truncate table [myTable]
INSERT INTO myTable (chosenDate, timeSchedule) 
VALUES 
('06/07/2015', '00100110'),
('06/07/2015', '00010100'),
('06/07/2015', '00110000'),
('06/07/2015', '00110011');
GO

select * from myTable
GO

;With MyCTE as (
    select 
        SUBSTRING([timeSchedule],1,1) as c1,
        SUBSTRING([timeSchedule],2,1) as c2,
        SUBSTRING([timeSchedule],3,1) as c3,
        SUBSTRING([timeSchedule],4,1) as c4,
        SUBSTRING([timeSchedule],5,1) as c5,
        SUBSTRING([timeSchedule],6,1) as c6,
        SUBSTRING([timeSchedule],7,1) as c7,
        SUBSTRING([timeSchedule],8,1) as c8,
        SUBSTRING([timeSchedule],9,1) as c9
    from myTable
)
select 
    CONVERT( NVARCHAR(50),CASE WHEN SUM(CONVERT(INT,c1)) > 0 THEN 1 ELSE 0 END)+
    CONVERT( NVARCHAR(50),CASE WHEN SUM(CONVERT(INT,c2)) > 0 THEN 1 ELSE 0 END)+
    CONVERT( NVARCHAR(50),CASE WHEN SUM(CONVERT(INT,c3)) > 0 THEN 1 ELSE 0 END)+
    CONVERT( NVARCHAR(50),CASE WHEN SUM(CONVERT(INT,c4)) > 0 THEN 1 ELSE 0 END)+
    CONVERT( NVARCHAR(50),CASE WHEN SUM(CONVERT(INT,c5)) > 0 THEN 1 ELSE 0 END)+
    CONVERT( NVARCHAR(50),CASE WHEN SUM(CONVERT(INT,c6)) > 0 THEN 1 ELSE 0 END)+
    CONVERT( NVARCHAR(50),CASE WHEN SUM(CONVERT(INT,c7)) > 0 THEN 1 ELSE 0 END)+
    CONVERT( NVARCHAR(50),CASE WHEN SUM(CONVERT(INT,c8)) > 0 THEN 1 ELSE 0 END)+
    CONVERT( NVARCHAR(50),CASE WHEN SUM(CONVERT(INT,c9)) > 0 THEN 1 ELSE 0 END)
from MyCTE

答案 1 :(得分:2)

首先需要的是获取字符串并将其转换为#的方法。因此,您需要创建一个新的标量函数(从here借用)。

CREATE FUNCTION [dbo].[BinaryToDecimal]
(
    @Input varchar(255)
)
RETURNS bigint
AS
BEGIN

    DECLARE @Cnt tinyint = 1
    DECLARE @Len tinyint = LEN(@Input)
    DECLARE @Output bigint = CAST(SUBSTRING(@Input, @Len, 1) AS bigint)

    WHILE(@Cnt < @Len) BEGIN
        SET @Output = @Output + POWER(CAST(SUBSTRING(@Input, @Len - @Cnt, 1) * 2 AS bigint), @Cnt)

        SET @Cnt = @Cnt + 1
    END

    RETURN @Output  

END

然后你可以简单地使用:

SUM([dbo].[BinaryToDecimal](timeSchedule))

然后将其包装在另一个函数中以将其转换回字符串表示形式。 This就是一个很好的例子。

顺便说一句,将二进制文件存储为字符串几乎总是错误的方法。

答案 2 :(得分:0)

您可以使用以下查询对表格的字段1中包含的每个0[timeSchedule]字符执行按位OR:

;WITH Tally (n) AS
(   
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
    FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) a(n)
    CROSS JOIN (VALUES(0),(0),(0),(0),(0)) b(n)   
), CTE AS (
   SELECT n, MAX(x.c) AS bitwiseOR
   FROM mytable
   CROSS JOIN Tally
   CROSS APPLY (SELECT SUBSTRING([timeSchedule], n, 1)) AS x(c)
   GROUP BY n
)
SELECT ( 
   SELECT CAST(bitwiseOR AS VARCHAR(MAX)) 
   FROM CTE AS t         
   WHERE bitwiseOR <> ''
   ORDER BY n
   FOR XML PATH('')) AS sumBoolean

我们的想法是使用计数表来'爆炸' [timeSchedule]列的每个字符。然后使用MAX对每个位位置执行按位OR运算。最后,使用FOR XML PATH将所有单个位连接成一个字符串。

注意:此查询甚至适用于[timeSchedule]可变长度值,即对于长度介于1到50之间的列中包含的任何值

Demo here

答案 3 :(得分:0)

以下是另外两个解决方案:-) 逻辑是一样的。但是一旦我在实践中看到了我的解决方案,我意识到我不需要使用SUM,因为我们只需要选择MAX。接下来因为CHAR 1在大多数整理(文化)中超过char 0(char而不是数字),所以我们也不需要任何CONVERT,我们可以从CHAR中选择MAX。所以这是两个解决方案:

-- This solution fit all
;With MyCTE as (
    select 
        SUBSTRING([timeSchedule],1,1) as c1,
        SUBSTRING([timeSchedule],2,1) as c2,
        SUBSTRING([timeSchedule],3,1) as c3,
        SUBSTRING([timeSchedule],4,1) as c4,
        SUBSTRING([timeSchedule],5,1) as c5,
        SUBSTRING([timeSchedule],6,1) as c6,
        SUBSTRING([timeSchedule],7,1) as c7,
        SUBSTRING([timeSchedule],8,1) as c8,
        SUBSTRING([timeSchedule],9,1) as c9
    from myTable
)
select 
    CONVERT( NVARCHAR(50),MAX(CONVERT(INT,c1)))+
    CONVERT( NVARCHAR(50),MAX(CONVERT(INT,c2)))+
    CONVERT( NVARCHAR(50),MAX(CONVERT(INT,c3)))+
    CONVERT( NVARCHAR(50),MAX(CONVERT(INT,c4)))+
    CONVERT( NVARCHAR(50),MAX(CONVERT(INT,c5)))+
    CONVERT( NVARCHAR(50),MAX(CONVERT(INT,c6)))+
    CONVERT( NVARCHAR(50),MAX(CONVERT(INT,c7)))+
    CONVERT( NVARCHAR(50),MAX(CONVERT(INT,c8)))+
    CONVERT( NVARCHAR(50),MAX(CONVERT(INT,c9)))
from MyCTE

-- MAX char depends on collate (like sorting, comparing)
-- but this solution fit most collate as least, if not all,
-- since "1" bigger than "0"
-- In this solution you need to remember that you will not get the "zero padding"
-- the solution will be in the len of the bigger len
;With MyCTE as (
    select 
        SUBSTRING([timeSchedule],1,1) as c1,
        SUBSTRING([timeSchedule],2,1) as c2,
        SUBSTRING([timeSchedule],3,1) as c3,
        SUBSTRING([timeSchedule],4,1) as c4,
        SUBSTRING([timeSchedule],5,1) as c5,
        SUBSTRING([timeSchedule],6,1) as c6,
        SUBSTRING([timeSchedule],7,1) as c7,
        SUBSTRING([timeSchedule],8,1) as c8,
        SUBSTRING([timeSchedule],9,1) as c9
    from myTable
)
select 
    MAX(c1)+
    MAX(c2)+
    MAX(c3)+
    MAX(c4)+
    MAX(c5)+
    MAX(c6)+
    MAX(c7)+
    MAX(c8)+
    MAX(c9)
from MyCTE