SQL应该格式化输出还是只检索原始数据?

Cha*_*adD 4 sql

一般来说,我编写的SQL查询返回未格式化的数据,并将其留给表示层,网页或Windows应用程序,以根据需要格式化数据.与我合作的其他人,包括我的老板,将坚持让数据库更有效率.我不确定我是否会购买它并相信即使通过让数据库执行可获得的可衡量的性能提升,也有更有说服力的理由来避免这种情况.

例如,我将查询放在数据访问层中,目的是尽可能重用查询.鉴于此,我确定如果数据保持其本机类型而不是将数据转换为字符串并在其上应用格式化函数,则更有可能重用查询,例如,将日期列格式化为DD -MMM-YYYY格式用于显示.当然,如果SQL将日期作为格式化字符串返回,您可以反转该过程以将值恢复为日期数据类型,但这似乎很尴尬,因为缺少更好的单词.Furtehrmore,当涉及到格式化其他数据时,例如,机器序列号由前缀,基数和后缀组成,每个子字段中删除了分隔符号和前导零,您可能会有可能无法正确向另一个方向转回原始序列号.也许这是一个糟糕的例子,但我希望你看到我的方向......

为了更进一步,我看到人们编写非常复杂的SQL,因为它们本质上是将我称之为表示逻辑的内容写入SQL而不是返回简单数据,然后在表示层中应用此表示逻辑.在我看来,这导致非常复杂,难以维护和更脆弱的SQL,不太适应变化.

以下我在系统中发现的实际例子,告诉我你的想法.我给这种方法的理性是,这使得Web应用程序非常简单地呈现页面,因为它在经典ASP Web应用程序中使用以下1行经典ADO逻辑片段来处理返回的行:

     oRS.GetString ( , , "</td>" & vbCrLf & "<td style=""font-size:x-small"" nowrap>" ,"</td>" & vbCrLf & "</tr>" & vbCrLf & "<tr>" & vbCrLf & _
     "<td style=""font-size:x-small"" nowrap>" ,"&nbsp;" ) & "</td>" & vbCrLf & "</tr>" & vbCrLf & _
Run Code Online (Sandbox Code Playgroud)

这是SQL本身.虽然我很欣赏作者编写复杂SQL的能力,但我觉得这是一个维护噩梦.我疯了吗?SQL返回当前针对我们的数据库运行的程序列表以及每个程序的状态:

因为我粘贴在这里时SQL没有显示CR/LF,所以我决定将SQL放在一个空的个人Google网站上.请随意发表评论.谢谢.

顺便说一句 - 这个SQL实际上是使用VB脚本嵌套在一个经典的ASP页面上构建的,而不是调用存储过程,所以你有嵌入式连接和引用标记的额外复杂性,如果你知道我的意思,更不用说缺乏格式.当我被要求帮助调试SQL时,我做的第一件事就是添加SQL输出的debug.print并将其抛出我刚刚找到的SQL格式化程序.在粘贴以下链接时丢失了一些格式:

编辑(Andomar):复制内联:(删除外部链接,谢谢 - 乍得)

SELECT 
Substring(Datename("dw",start_datetime),1,3) 
+ ', '
+ Cast(start_datetime AS VARCHAR) "Start Time (UTC/GMT)"
,program_name "Program Name"
,run_sequence "Run Sequence"
,CASE 
WHEN batchno = 0
THEN Char(160)
WHEN batchno = NULL
THEN Char(160)
ELSE Cast(batchno AS VARCHAR)
END "Batch #" /* ,Replace(Replace(detail_log ,'K:\' ,'file://servernamehere/DiskVolK/') ,'\' ,'/') "log"*/ /* */
,Cast('<a href="GOIS_ViewLog.asp?Program_Name=' AS VARCHAR(99))
+ Cast(program_name AS VARCHAR)
+ Cast('&Run_Sequence=' AS VARCHAR)
+ Cast(run_sequence AS VARCHAR)
+ Cast('&Page=1' AS VARCHAR)
+ ''
+ Cast('">'
+ CASE 
WHEN end_datetime >= start_datetime
THEN CASE 
WHEN end_datetime <> 'Jan 1 1900 2:00 PM'
THEN CASE 
WHEN (success_code = 10
OR success_code = 0)
AND exit_code = 10
THEN CASE 
WHEN errorcount = 0
THEN 'Completed Successfully'
ELSE 'Completed with Errors'
END
WHEN success_code = 100
AND exit_code = 10
THEN 'Completed with Errors'
ELSE CASE 
WHEN program_name <> 'FileDepCheck'
THEN 'Failed'
ELSE 'File not found'
END
END
ELSE CASE 
WHEN success_code = 10
AND exit_code = 0
THEN 'Failed; Entries for Input File Missing'
ELSE 'Aborted'
END
END
ELSE CASE 
WHEN ((Cast(Datediff(mi,start_datetime,Getdate()) AS INT) <= 240)
OR ((SELECT 
Count(* )
FROM 
MASTER.dbo.sysprocesses a(nolock)
INNER JOIN gcsdwdb.dbo.update_log b(nolock)
ON a.program_name = b.program_name
WHERE a.program_name = update_log.program_name
AND (Abs(Datediff(n,b.start_datetime,a.login_time))) < 1) > 0))
THEN 'Processing...'
ELSE 'Aborted without end date'
END
END
+ '</a>' AS VARCHAR) "Status / Log"
,Cast('<a href="' AS VARCHAR)
+ Replace(Replace(detail_log,'K:\','file://servernamehere/DiskVolK/'),
'\','/')
+ Cast('" title="Click to view Detail log text file"' AS VARCHAR(99))
+ Cast('style="font-family:comic sans ms; font-size:12; color:blue"><img src="images\DetailLog.bmp" border="0"></a>' AS VARCHAR(999))
+ Char(160)
+ Cast('<a href="' AS VARCHAR)
+ Replace(Replace(summary_log,'K:\','file://servernamehere/DiskVolK/'),
'\','/')
+ Cast('" title="Click to view Summary log text file"' AS VARCHAR(99))
+ Cast('style="font-family:comic sans ms; font-size:12; color:blue"><img src="images\SummaryLog.bmp" border="0"></a>' AS VARCHAR(999)) "Text Logs"
,errorcount "Error Count"
,warningcount "Warning Count"
,(totmsgcount
- errorcount
- warningcount) "Information Message Count"
,CASE 
WHEN end_datetime > start_datetime
THEN CASE 
WHEN Cast(Datepart("hh",(end_datetime
- start_datetime)) AS INT) > 0
THEN Cast(Datepart("hh",(end_datetime
- start_datetime)) AS VARCHAR)
+ ' hr '
ELSE ' '
END
+ CASE 
WHEN Cast(Datepart("mi",(end_datetime
- start_datetime)) AS INT) > 0
THEN Cast(Datepart("mi",(end_datetime
- start_datetime)) AS VARCHAR)
+ ' min '
ELSE ' '
END
+ CASE 
WHEN Cast(Datepart("ss",(end_datetime
- start_datetime)) AS INT) > 0
THEN Cast(Datepart("ss",(end_datetime
- start_datetime)) AS VARCHAR)
+ ' sec '
ELSE ' '
END
ELSE CASE 
WHEN end_datetime = start_datetime
THEN '< 1 sec'
ELSE CASE 
WHEN ((Cast(Datediff(mi,start_datetime,Getdate()) AS INT) <= 240)
OR ((SELECT 
Count(* )
FROM 
MASTER.dbo.sysprocesses a(nolock)
INNER JOIN gcsdwdb.dbo.update_log b(nolock)
ON a.program_name = b.program_name
WHERE a.program_name = update_log.program_name
AND (Abs(Datediff(n,b.start_datetime,a.login_time))) < 1) > 0))
THEN 'Running '
+ Cast(Datediff(mi,start_datetime,Getdate()) AS VARCHAR)
+ ' min'
ELSE '&nbsp;'
END
END
END "Elapsed Time" /* ,end_datetime "End Time (UTC/GMT)" ,datepart("hh" ,
(end_datetime - start_datetime)) "Hr" ,datepart("mi" ,(end_datetime - start_datetime)) "Mins" ,datepart("ss" ,(end_datetime - start_datetime)) "Sec" ,datepart("ms" ,(end_datetime - start_datetime)) "mSecs" ,datepart("dw" ,start_datetime) "dp" ,case when datepart("dw" ,start_datetime) = 6 then ' Fri' when datepart("dw" ,start_datetime) = 5 then ' Thu' else '1' end */
,totalrows "Total Rows"
,inserted "Rows Inserted"
,updated "Rows Updated" /* ,success_code "succ" ,exit_code "exit" */
FROM 
update_log
WHERE start_datetime >= '5/29/2009 16:15'
ORDER BY start_datetime DESC
Run Code Online (Sandbox Code Playgroud)

小智 16

答案显然是"只是检索输出".在SQL Server上格式化具有以下问题:

  • 它增加了来自SQL服务器的网络流量
  • SQL具有非常差的字符串处理功能
  • SQL服务器未优化以执行字符串操作
  • 您正在使用服务器CPU周期,可以更好地用于查询处理
  • 它可能使查询优化器的生活变得困难(或不可能)
  • 您必须编写更多查询以支持不同的格式
  • 您可能必须编写不同的查询以支持不同浏览器上的格式
  • 您不能为不同目的重复使用查询

我相信还有更多.


pax*_*blo 6

SQL应该不会被格式化,期.它是用于SELECT从数据库中提取(使用时)数据的关系代数.

让DBMS为您格式化数据是错误的,这应该留给您自己的代码(在DBMS之外).DBMS通常负载不足,无需为您进行演示工作.它还针对数据检索而非演示进行了优化.

我知道如果我尝试做类似的事情,DBA会要求立即执行:-)


Kaz*_*zar 5

在SQL中格式化输出的概念确实打破了表示和数据分离的整个概念,不仅如此,而且可能会出现许多条件:

  • 如果您需要本地化日期格式怎么办?例如,英国对美国使用不同的日期格式 - 您是否正在进行国际化,直至数据层?

  • 如果格式规则发生变化怎么办?即某些文本需要以不同的方式格式化以符合一些新的公司政策?同样,您需要一直回到数据层.

  • 如果我们采用网络环境,您如何决定逃避价值?如果要输出到网页,JSON或其他地方,可能需要使用不同形式的转义...

不仅如此,SQL字符串操作函数通常也不是非常活泼.