Sql server 转换列名而不是值的SQL

Sql server 转换列名而不是值的SQL,sql-server,tsql,Sql Server,Tsql,我有一个Surveys表,其中包括几个布尔列(其中0=false,1=true)。我要做的是创建另一个表,其中一列包含这些列的名称,另一列计算真实(1)出现的百分比。基于,我创建了一个T-SQL脚本来执行此操作: /****** Drop existing table ******/ DROP TABLE [dbo].[PercUsedFor] GO /****** Drop existing calculated values ******/ IF OBJECT_ID('GetPercUse

我有一个Surveys表,其中包括几个布尔列(其中0=false,1=true)。我要做的是创建另一个表,其中一列包含这些列的名称,另一列计算真实(1)出现的百分比。基于,我创建了一个T-SQL脚本来执行此操作:

/****** Drop existing table ******/
DROP TABLE [dbo].[PercUsedFor]
GO

/****** Drop existing calculated values ******/
IF OBJECT_ID('GetPercUsed', 'FN') IS NOT NULL
  DROP FUNCTION GetPercUsed
GO

/****** Calculate new values ******/
CREATE FUNCTION GetPercUsed (@Task nvarchar)
RETURNS DECIMAL
AS
BEGIN
  DECLARE @Total INT
  SELECT @Total = COUNT(*) FROM Surveys

  DECLARE @Count INT
  SELECT @Count = COUNT(*) FROM Surveys WHERE @Task = 1

  DECLARE @Percent DECIMAL
  SELECT @Percent = ((@Count / @Total) * 100)

  RETURN @Percent
END
GO

/****** Create new table ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[PercUsedFor](
    [Task] [nvarchar](50) NULL,
    [PercUsed] AS ([dbo].GetPercUsed(Task))
)
GO

/****** Fill in values ******/
INSERT INTO [dbo].[PercUsedFor] (Task)
SELECT 'Volume'
SELECT 'Speed'
SELECT 'Gap'
SELECT 'Length'
SELECT 'Stats'
GO

/****** Show table ******/
SELECT * FROM [dbo].[PercUsedFor]
GO
当我运行此命令时,将创建表,但最后一行

SELECT * FROM [dbo].[PercUsedFor]" 
给我一个错误

将nvarchar值“V”转换为数据类型时,转换失败 内部的

我看到的唯一可能是导致这种情况的原因是在

SELECT @Count = COUNT(*) FROM Surveys WHERE @Task = 1
就像它试图将
@Task
(即
“Volume”
)的值转换为
int
,而不是在
调查中为该列查找
'1'
的实例一样

我怎样才能解决这个问题?我怎样才能在Where子句中正确使用具有动态列名的查询

select .. where 'V' = 1
无效,因为它将尝试将
V
强制为
int

select .. where 'V' = '1'
如果您传递了
'Volume'
,那么由于您的
@Task nvarchar
没有大小,它将默认为1个字符(
V

。。。在Where子句中使用具有动态列名的查询

select .. where 'V' = 1

如果您打算使用
@Task
作为列名,那么这将不起作用,您需要使用您不希望在WHERE子句中使用输入变量

为了实现这一点,我必须发明一个调查表。这是我用过的

CREATE TABLE dbo.[Surveys]
    (
    SurveyID bigint identity (1,1) NOT NULL,
    SurveyName [nvarchar](max) NULL,
    SurveyStarted bit null,
    SurveyCompleted bit null,
    SurveyBilled bit null,
    SurveyPaid bit null,
    SurveyCanceled bit null
    )

INSERT INTO Surveys (SurveyName, SurveyStarted, SurveyCompleted, SurveyBilled, SurveyPaid, SurveyCanceled) VALUES ('Survey 1', 1, 1, 1, 1, 0)
INSERT INTO Surveys (SurveyName, SurveyStarted, SurveyCompleted, SurveyBilled, SurveyPaid, SurveyCanceled) VALUES ('Survey 2', 0, 0, 0, 0, 1)
INSERT INTO Surveys (SurveyName, SurveyStarted, SurveyCompleted, SurveyBilled, SurveyPaid, SurveyCanceled) VALUES ('Survey 3', 1, 0, 0, 0, 0)
INSERT INTO Surveys (SurveyName, SurveyStarted, SurveyCompleted, SurveyBilled, SurveyPaid, SurveyCanceled) VALUES ('Survey 4', 1, 1, 1, 0, 0)
INSERT INTO Surveys (SurveyName, SurveyStarted, SurveyCompleted, SurveyBilled, SurveyPaid, SurveyCanceled) VALUES ('Survey 5', 1, 1, 0, 0, 0)
我仍然在用一个函数来实现这一点,但我认为答案在于执行UNPIVOT以获取所有的位字段作为值,然后使用WHERE子句中的输入变量来处理那些以字段值为轴的列名

好的,如果你在函数中使用这个

SELECT
    ThingType, 
    SUM(CONVERT(int, ThingState)) AS [Count]
FROM
    (
    SELECT SurveyName, ThingType, ThingState FROM Surveys 
    UNPIVOT
        (
        ThingState FOR ThingType IN (SurveyStarted, SurveyCompleted, SurveyBilled, SurveyPaid, SurveyCanceled)
        ) Unpivoted
    ) DerivedUnpivoted
GROUP BY
    [ThingType]

…您应该能够将WHERE子句钉在它的底部,以便只获得一行用于计算@Count变量,然后按照您的意图进行其余的计算。这完全避免了动态SQL

如果我理解了这个问题,就会有一个非常简单、非常有效的答案
SQL没有布尔值,它有位
位false=0,位True=1
你们不能在比特上求和,但你们可以把它转换成tinyint,然后求和

运行此命令或仅使用它创建视图

  select sum(cast(question1 as tinyint)) / cast(count(*) as numeric) as [Q1pct]
       , sum(cast(question2 as tinyint)) / cast(count(*) as numeric) as [Q2pct] 
    from [Survery]
对于现有的查询,有几个问题:

(@Task nvarchar)
nvarchar的默认宽度为1,因此将被截断

@任务=1
1是一个整数,因此您将得到一个转换错误
需要@Task='1'

您没有一项任务是“1”

根本不清楚你的意思,而不是在该专栏的调查中找到“1”的实例

我想你是说

SELECT @Count = COUNT(*) FROM Surveys WHERE Task = @Task 
即使这样,你也会遇到一些问题

SELECT @Percent = ((@Count / @Total) * 100)
As integer将向下舍入为0

SELECT @Percent = (100* @Count / @Total)
即使在上面,也将舍入为和整数

SELECT @Percent = (100* cast(@Count as decimal) / @Total)

两方面都谢谢你。你链接的那个线程包含了一个关于动态SQL的文章的链接。通过这个例子和其他例子,我设法弄明白了如何修改SELECT语句。然而,事实证明,您不能在用户定义的函数中使用动态SQL。我能想到的管理我正在尝试做的事情的唯一其他方法是对每个特定任务强制计算。你有没有更好的建议?