如何对 SQL select 执行布尔加法
How to perform boolean addition on an SQL select
我在名为 timeSchedule
的数据库 table 列中有以下数据
00100110
00010100
00110000
00110011
布尔加法会得到
00110111
在 sql 中有没有办法做到这一点?类似于 myTable
中的 select 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’);
您首先需要的是获取字符串并将其转换为 # 的方法。因此,您需要创建一个新的标量函数(借用 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 就是一个很好的例子。
顺便说一句,将二进制存储为字符串几乎总是错误的方法。
您可以使用以下查询对 table 的字段 [timeSchedule]
中包含的每个 1
、0
字符执行按位或:
;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
想法是使用计数 table 以便 'explode' [timeSchedule]
列的每个字符。然后使用MAX
对每个位位置进行按位或运算。最后,使用 FOR XML PATH
将所有单个位连接成一个字符串。
注意:此查询甚至对 [timeSchedule]
的 可变长度 值也有效,即对于包含在长度在 1 到 50 之间的列。
好的,现在我们有了 DDL(遗憾的是没有 DML,只有一行)。我们可以提供解决方案:-)
第一!我强烈建议不要使用上面的解决方案,不需要循环 即使你不使用我们知道最大长度 (50) 的固定数据长度。
其次!如果您要解析文本,那么您应该使用 SQLCLR 而不是使用 T-SQL 循环和解析,在大多数情况下也是如此。
第三 :-) 这是简单解决方案的简单示例。我只使用了前 10 个字符......你可以继续使用 50 个......如果你不想自己手动编写查询,你可以使用动态查询来创建查询(还有其他解决方案,我建议检查为了select你的最佳解决方案而使用的执行计划和IO):
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
这里还有两个解决方案:-)
逻辑是一样的。但是当我在实践中看到我的解决方案后,我意识到我不需要使用 SUM,因为我们只需要选择 MAX。接下来,由于在大多数整理(文化)中 CHAR 1 大于 char 0(char 而不是数字),因此我们也不需要任何 CONVERT,我们可以 select 来自 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
我在名为 timeSchedule
的数据库 table 列中有以下数据00100110
00010100
00110000
00110011
布尔加法会得到
00110111
在 sql 中有没有办法做到这一点?类似于 myTable
中的 select 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’);
您首先需要的是获取字符串并将其转换为 # 的方法。因此,您需要创建一个新的标量函数(借用 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 就是一个很好的例子。
顺便说一句,将二进制存储为字符串几乎总是错误的方法。
您可以使用以下查询对 table 的字段 [timeSchedule]
中包含的每个 1
、0
字符执行按位或:
;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
想法是使用计数 table 以便 'explode' [timeSchedule]
列的每个字符。然后使用MAX
对每个位位置进行按位或运算。最后,使用 FOR XML PATH
将所有单个位连接成一个字符串。
注意:此查询甚至对 [timeSchedule]
的 可变长度 值也有效,即对于包含在长度在 1 到 50 之间的列。
好的,现在我们有了 DDL(遗憾的是没有 DML,只有一行)。我们可以提供解决方案:-)
第一!我强烈建议不要使用上面的解决方案,不需要循环 即使你不使用我们知道最大长度 (50) 的固定数据长度。
其次!如果您要解析文本,那么您应该使用 SQLCLR 而不是使用 T-SQL 循环和解析,在大多数情况下也是如此。
第三 :-) 这是简单解决方案的简单示例。我只使用了前 10 个字符......你可以继续使用 50 个......如果你不想自己手动编写查询,你可以使用动态查询来创建查询(还有其他解决方案,我建议检查为了select你的最佳解决方案而使用的执行计划和IO):
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
这里还有两个解决方案:-) 逻辑是一样的。但是当我在实践中看到我的解决方案后,我意识到我不需要使用 SUM,因为我们只需要选择 MAX。接下来,由于在大多数整理(文化)中 CHAR 1 大于 char 0(char 而不是数字),因此我们也不需要任何 CONVERT,我们可以 select 来自 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