我在名为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’);
答案 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之间的列中包含的任何值
答案 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