早安,
我想问一下,有没有更简单的方法来获取一组非空的列?
场景
我有一个可从excel获取数据的上传器。该代码正在运行,但陷入僵局。我想修改我的代码,因为我正在执行平均RBAR(行排成一行)
代码
ALTER procedure [dbo].[saveProdPropSampDta]
@PartNo as nvarchar(20),
@PPFno as nvarchar(20),
@Dimension as nvarchar(30),
@ToUpdate as nvarchar(10),
@count as nvarchar(2),
@Judgement as nvarchar(2)
as
declare @TSQL as nvarchar(max)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
begin
--remove spaces from variable @dimension
set @Dimension = REPLACE(@Dimension, ' ','')
--ToUpdate is the value of from Excel
set @TSQL = 'update ProductProperty set T'+@count+' = @ToUpdate where Partno = @Partno and PPFno = @PPFno and DName = @Dimension';
exec sp_executesql @TSQL, N'@PartNo nvarchar(20), @PPFno nvarchar(20), @Dimension as nvarchar(30), @ToUpdate as nvarchar(10), @count as nvarchar(2)', @PartNo, @PPFno , @Dimension, @ToUpdate, @count;
declare @cursor CURSOR
declare @colname as nvarchar(30)
declare @top as integer
declare @query as nvarchar(MAX)
declare @topass as nvarchar(MAX) = ''
declare @retVal nvarchar(30)
declare @categoryid NVARCHAR(MAX)
SET @cursor = CURSOR LOCAL FOR
(select [Name] from sys.columns where object_id = (select object_id from sys.tables where name = 'ProductProperty') and [Name] like 'T%' and [name] <> 'TEMP')order by [Name] asc
--Gets column names from table from T1 -> T45
OPEN @cursor
FETCH NEXT
FROM @cursor INTO @colname
WHILE @@FETCH_STATUS = 0
BEGIN
SET @query = N'set @categoryid = (select distinct ' + @colname + ' from ProductProperty
where PartNo = @PartNo and PPFNo = @PPFno and DName = @Dimension)';
--
EXEC sp_executesql @query,
N'@PartNo nvarchar(20), @PPFno nvarchar(20),@Dimension
nvarchar(30), @categoryid NVARCHAR(MAX) OUTPUT', @PartNo, @PPFno,@Dimension,
@categoryid OUTPUT
if @categoryid is not null
begin
set @topass = @topass + @colname + '+'
end
FETCH NEXT
FROM @cursor INTO @colName
END
CLOSE @cursor
DEALLOCATE @cursor
set @topass = LEFT(@topass, LEN(@topass)-1)
set @topass = N'set @categoryid = (Select cast(('+@topass+')/'+@count+' as decimal(18,3)) from ProductProperty where PartNo = @PartNo and PPFNo = @PPFno and DName = @Dimension)';
EXEC sp_executesql @topass,
N'@PartNo nvarchar(20), @PPFno nvarchar(20),@Dimension
nvarchar(30), @categoryid NVARCHAR(MAX) OUTPUT', @PartNo, @PPFno,@Dimension,
@categoryid OUTPUT
set @topass = 'update ProductProperty set average = '+@categoryid+', Judgement = '''+@Judgement+''' where PartNo = @PartNo and PPFNo = @PPFno and DName = @Dimension';
EXEC sp_executesql @topass,
N'@PartNo nvarchar(20), @PPFno nvarchar(20),@Dimension
nvarchar(30)', @PartNo, @PPFno,@Dimension
end
此类代码的原因
该代码将在VB.Net代码中每次调用时运行,它将从变量获取数据到存储过程中。该代码实际上是从不为空的列中求平均值的。
我想拥有的东西 是否有类似的东西
select ave(ifnull(T1.....T2,If Null dont include, ifnot null include)) from TABLE
答案 0 :(得分:1)
我可能有几种方法可以重新设计您的解决方案。
如果您只能进行更改,则#2可能是门票。但是我个人的偏好是#1-生成的代码更简单,并且如果您决定需要T46,则无需进行任何更改。
方法1:
您尚未提供表的完整详细信息,因此我猜您有一个构成主键的ID
列,否则,我们将在新解决方案中添加一个:)
我还要假设您是根据需要而不是通过选择将nvarchar
参数接收到存储的proc中,并相应地声明数据类型。
是否完全可以重新设计数据模型?一种解决方法是将“ T1” ..“ T45”列移到单独的表中,并将它们视为行。
您可以从以下表格中找到
:Create Table ProductProperty
(
ID int identity,
Partno nvarchar(20),
PPFno nvarchar(20),
DName nvarchar(30),
T1 decimal(18, 3),
T2 decimal(18, 3),
T3 decimal(18, 3),
-- ...
T44 decimal(18, 3),
T45 decimal(18, 3),
average decimal(18, 3),
Judgement nvarchar(2)
)
到
Create Table ProductProperty
(
ID int identity,
Partno nvarchar(20),
PPFno nvarchar(20),
DName nvarchar(30),
average decimal(18, 3),
Judgement nvarchar(2)
) -- You would probably want to put a unique index on (Partno, PPFno, DName)
Create Table ProductPropertyT
(
ProductPropertyID int,
TNo nvarchar(2),
TValue decimal(18, 3)
)
现在,您的存储过程只需要标识主键值(根据我对复合键Partno
,PPFno
和DName
的推测),即可在{中创建或更新一条记录{1}}表,并对ProductPropertyT
值匹配的记录进行TValue
的简单平均:
ProductPropertyId
现在存储的proc是:更短;没有动态SQL;很容易理解。
方法2:
如果您绝对必须具有此数据模型,则可以使用alter procedure [dbo].[saveProdPropSampDta]
@PartNo as nvarchar(20),
@PPFno as nvarchar(20),
@Dimension as nvarchar(30),
@ToUpdate as nvarchar(10),
@count as nvarchar(2),
@Judgement as nvarchar(2)
as
begin
--remove spaces from variable @dimension
set @Dimension = REPLACE(@Dimension, ' ','')
-- determine the PK
declare @pk int
select @pk = ID from ProductProperty where Partno = @Partno and PPFno = @PPFno and DName = @Dimension
-- create / update the value in the ProductPropertyT table
if exists (select * from ProductPropertyT where ProductPropertyID = @pk and TNo = @count)
begin
update ProductPropertyT
set TValue = cast(@ToUpdate as decimal(18, 3))
where ProductPropertyID = @pk and TNo = @count
end
else
begin
insert into ProductPropertyT (ProductPropertyID, TNo, TValue)
values (@pk, @count, cast(@ToUpdate as decimal(18, 3)))
end
-- update the average and judgement in the ProductProperty table.
update ProductProperty
set average = (select avg(TValue) from ProductPropertyT where ProductPropertyID = @pk)
,Judgement = @Judgement
where ID = @pk
end
从T1 ... T45列中获取非空值,然后对它们进行平均。
unpivot
我会将其保留为练习,以将其织入一条update语句中-但足以说明您在过程的这一部分不需要任何动态sql。
希望有帮助。
答案 1 :(得分:0)
我想你需要这样的东西。
SELECT AVG(CASE WHEN T1 IS NOT NULL THEN T1 ELSE 0 END)
FROM TABLE