SQL转换列名而不是值

时间:2015-06-22 15:35:32

标签: sql-server tsql

我有一个Surveys表,其中包含几个布尔列(其中0 = false和1 = true)。我尝试做的是另一个表,其中1列包含这些列的名称,另一列计算真(1)次出现的百分比。基于this reference,我创建了一个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'中找到Surveys的实例1}}用于该列。

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

3 个答案:

答案 0 :(得分:3)

V

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

'Volume'

如果您通过了@Task nvarchar,那么当V没有尺寸时,它将默认为1个字符(@Task

  

...在Where子句中使用带有动态列名的查询?

如果您打算将name = [] start_years = [] end_years = [] party = [] for line in lines.split('\n'): fields = line.split(',') name.append(fields[:-2][0].split(' ')[-1]) dates = fields[-2].replace(' ', '').split('-') start_years.append(dates[0]) end_years.append(dates[1]) party.append(fields[-1].replace(' ', '')) print name print start_years print end_years print party 用作列名称,这将无效,您需要使用Dynamic SQL

答案 1 :(得分:0)

您不希望WHERE子句中的输入变量。

为了完成这项工作,我不得不发明一个Surveys表。这是我用过的......

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。

答案 2 :(得分:0)

如果我理解这个问题,那么答案是非常容易和非常有效的 SQL没有布尔值,它有比特
位false = 0且位True = 1 您无法对Bit求和,但您可以将其转换为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,因此它会被截断

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

你没有“1'”的任务。

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

我认为你的意思是

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

即使这样,你也会遇到问题

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

因为整数将向下舍入为0

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

即使是上面也会向下舍入到整数

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