重复 SQL 语句的最佳实践
Posted
技术标签:
【中文标题】重复 SQL 语句的最佳实践【英文标题】:Best Practice for Repeating SQL Statements 【发布时间】:2013-05-10 17:06:45 【问题描述】:我正在寻找一种更好的方法来编写高度重复的 sql 语句。我知道我可以通过例如使用 php 方法来做到这一点,但我想要一个纯 SQL 解决方案。我正在使用 Sybase。
select
"SvHKeyId"=sh.KeyId,
"Scale"="Partial PTSD",
"ScoreText"=convert(varchar(3),
(case
when
(case
when
1 in (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum between 1 and 13)
and 1 in (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum between 15 and 21)
and 1 in (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum between 22 and 26)
then 'Yes'
else 'No'
end)
= 'Yes'
and
(case
when
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=30) >= 2
or (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=32) >= 2
or (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=33) >= 2
or (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=29) >= 2
or (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=45) >= 2
then 1
else 0
end)
+
(case
when
(case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=36) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=44) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=42) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=34) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=35) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46) >= 2 then 1 else 0 end)
>= 3 then 1
else 0
end)
+
(case
when
(case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=40) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=43) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=28) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=39) >= 2 then 1 else 0 end)
>= 2 then 1
else 0
end)
>=2
then 'Yes'
else 'No'
end)
= 'Yes'
then 'Yes'
else 'No'
end)
),
"ScoreNum"=
(case
when
(case
when
1 in (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum between 1 and 13)
and 1 in (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum between 15 and 21)
and 1 in (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum between 22 and 26)
then 'Yes'
else 'No'
end)
= 'Yes'
and
(case
when
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=30) >= 2
or (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=32) >= 2
or (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=33) >= 2
or (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=29) >= 2
or (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=45) >= 2
then 1
else 0
end)
+
(case
when
(case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=36) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=44) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=42) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=34) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=35) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46) >= 2 then 1 else 0 end)
>= 3 then 1
else 0
end)
+
(case
when
(case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=40) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=43) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=28) >= 2 then 1 else 0 end)
+ (case when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=39) >= 2 then 1 else 0 end)
>= 2 then 1
else 0
end)
>=2
then 'Yes'
else 'No'
end)
= 'Yes'
then 1
else 0
end)
from
SurvHeader sh
where
sh.KeyId=105101
这是一个评分程序。我正在比较一系列子分数以得出总分。有没有更好的 SQL 方法?我想我可以使用存储过程?
这是一个更极端的例子,我使用了太多超出限制的子查询:
select
"SvHKeyId"=sh.KeyId,
"Scale"="Total",
"ScoreText"=convert(varchar(3),
(select sum(Resp) from SurvResp sr where sh.KeyId=sr.SvHKeyId
and QuestNum in (28,29,30,31,32,33,34,35,36,39,40,42,43,44,45,46) and Resp <> 5)
+
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37) <> 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38) <> 5
then
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37)
> (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37)
< (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37)
= (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
end)
else
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37) = 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38) = 5
then 0
else
(case
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37)
else 0
end)
end)
end)
+
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31) <> 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47) <> 5
then
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31)
> (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31)
< (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31)
= (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
end)
else
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31) = 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47) = 5
then 0
else
(case
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31)
else 0
end)
end)
end)
+
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46) <> 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48) <> 5
then
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46)
> (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46)
< (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46)
= (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
end)
else
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46) = 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48) = 5
then 0
else
(case
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46)
else 0
end)
end)
end)
),
"ScoreNum"=
(select sum(Resp) from SurvResp sr where sh.KeyId=sr.SvHKeyId
and QuestNum in (28,29,30,31,32,33,34,35,36,39,40,42,43,44,45,46) and Resp <> 5)
+
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37) <> 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38) <> 5
then
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37)
> (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37)
< (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37)
= (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
end)
else
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37) = 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38) = 5
then 0
else
(case
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38)
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=38) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=37)
else 0
end)
end)
end)
+
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31) <> 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47) <> 5
then
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31)
> (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31)
< (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31)
= (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
end)
else
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31) = 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47) = 5
then 0
else
(case
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47)
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=47) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=31)
else 0
end)
end)
end)
+
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46) <> 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48) <> 5
then
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46)
> (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46)
< (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46)
= (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
then
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
end)
else
(case
when
(select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46) = 5
and (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48) = 5
then 0
else
(case
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48)
when (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=48) = 5
then (select Resp from SurvResp sr where sh.KeyId=sr.SvHKeyId and sr.QuestNum=46)
else 0
end)
end)
end)
from
SurvHeader sh
where sh.KeyId=105101
【问题讨论】:
“我想要一个纯 SQL 解决方案” - 为什么?你目前所做的几乎无法阅读...... 也许纯 SQL 不是要走的路。我想探索这一点的原因是,使用纯 SQL 解决方案,评分过程变得独立于应用程序 - 所以它更便携。 同样,您可以说这段 SQL 代码非常限制性,将逻辑移动到应用程序将创建一个独立于 SQL 引擎的解决方案......或者,简而言之,它归结为this:你需要那种独立性吗? 【参考方案1】:这些文字中的大部分应该是数据,而不是代码。我强烈建议将这些巨大的开关重构为数据,以便更简单的查询可以评估它。这样,“纯 SQL”解决方案将更加可行,从长远来看,性能和维护都会更好。也许您可以加入一个Scoring
表并与之比较?
Scoring (Question, Answer, Result)
是一种概念上的可能性,希望不要过于简单化。
如前所述,"You can write FORTRAN in any language."
似乎是 T-SQL。
更新
如果这些计算已经完成,并且您在当前事务中更新了表,则无需仅仅因为它们尚未提交而重新执行它们。如果该事务中的任何查询在事务中较早更新,则该事务中的任何查询都将获取该事务的更新数据。
更多关于Sybase ASE transactions。
此外,您不应期望 GO
到 work in a stored procedure。它在您的 IDE 中用作批处理分隔符,而不是事务控制。
【讨论】:
它们实际上是作为数据保存到评分表中 - 先前的查询正在为先前的语句中的相同子量表生成分数。也许我的愚蠢行为是在同一个事务中进行 - 因为在事务完成之前我无法选择结果 - 这就是我有冗余的原因。当您在同一事务中时,有没有办法从尚未提交的事务中选择一个值?否则,如果我使用单独的事务并且出现问题,我可能会有孤立值。 在我看来,您仍然希望将所有这些case
s 表示为表格中的行。
当您在事务中时,您可以看到之前在该事务中所做的所有更改。
我相信引用我已经评分的子分数会更有效——它会大大减少切换的数量,而不会不必要地分割 sql 语句。
So if I..."begin transaction insert into table select 'KeyId'=123, 'Score'=45 go select * from table where KeyId = 123 ...我能得到分数吗? 以上是关于重复 SQL 语句的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章