【问题标题】:Interpolate a variable date in WHERE statement of SQL Query string在 SQL 查询字符串的 WHERE 语句中插入变量日期
【发布时间】:2020-06-30 12:45:36
【问题描述】:

我正在使用 .NET Web API2 开发 API。其中一个端点接收一个日期作为参数,它需要根据该日期返回一个项目列表。问题是我无法在 SQL 查询中插入这个日期。

假设我需要这个查询,如果我硬编码日期,它会起作用

Select platform_code, platform_state, COUNT(*) AS 'total cycle', MIN(events.created_at) AS 'first reading'
from events LEFT JOIN platforms ON platforms.platform_code = events.platform_code
WHERE events.created_at BETWEEN '22/06/2020 0:00:00' AND getdate() 
group by platform_code, platform_state

这是我的控制器代码:

{
    [RoutePrefix("api/queries")]
    public class QueriesController : ApiController
    {
        [Route("dashboard")]
        public HttpResponseMessage GetDashboard(string start_date = null)
        {
           DateTime parsed_start_date ;

            using (var ctx = new RFID_TESTEntities())
            {
                if (start_date != null)
                {
                     parsed_start_date = DateTime.ParseExact(start_date, "dd-MM-yyyy", new CultureInfo("es-ES"));

                }
                else
                {
                    parsed_start_date = DateTime.ParseExact("01-01-2020", "dd-MM-yyyy", new CultureInfo("es-ES"));
                }

                String query = "Select platform_code, platform_state, COUNT(*) AS 'total cycle', MIN(events.created_at) AS 'first reading'
                from events LEFT JOIN platforms ON platforms.platform_code = events.platform_code
                WHERE events.created_at BETWEEN " + parsed_start_date + "  AND getdate() 
                group by platform_code, platform_state";
                var platforms = ctx
                    .Database.SqlQuery<Dashboard>(query)
                    .ToList();

如果我尝试运行它,where 子句中的 parsed_start_date 变量缺少简单引号,因此出现 SQL 语法错误:

"Select platform_code, platform_state, COUNT(*) AS 'total cycle', MIN(events.created_at) AS 'first reading' from events LEFT JOIN platforms ON platforms.platform_code = events.platform_code
WHERE events.created_at BETWEEN 01/01/2020 0:00:00 AND getdate() 
group by platform_code, platform_state"

在查询中使用它之前,我尝试将变量转换为字符串,但显然它的行为方式相同。

【问题讨论】:

  • 使用参数而不是构建 sql 字符串。它将使您能够将其作为实际日期传递,并且您将避免语法错误。
  • 您确实应该使用参数。导致字符串出错的原因是缺少引号:BETWEEN '" + parsed_start_date + "'。如果仔细观察,它是:BETWEEN ' " + ... + " ' (双引号前后的单引号)。在写这么长的字符串时,我会使用 @"..." 字符串,这样你就可以写多行了。
  • 起初我使用的是 LINQ Lambda,但真正的查询比我在 OP 中显示的要复杂一些(为了清楚起见,我进行了简化)并且我无法将 SQL 转换为 LINQ,所以我决定尝试这种方式。
  • 我猜你的意思是传递这样一个参数:stackoverflow.com/questions/3216233/…,我会检查一下。

标签: c# .net asp.net-web-api2


【解决方案1】:

以防万一有人觉得它有用,这最终对我有用,使用 sql 参数,正如 cmets 所说,在安全性方面比我首先尝试做的要好得多:

 String query = "Select platform_code, platform_state, COUNT(*) AS 'total cycle', MIN(events.created_at) AS 'first reading'
                from events LEFT JOIN platforms ON platforms.platform_code = events.platform_code
                WHERE events.created_at BETWEEN @start_date  AND getdate() 
                group by platform_code, platform_state";
                var platforms = ctx
                    .Database.SqlQuery<Dashboard>(query, , new SqlParameter("@start_date", parsed_start_date))
                    .ToList();

【讨论】:

  • 干得好。我无法告诉你人们多久忽略使用参数的建议。
  • 这是最好的方法。为了获得更好的可见性,请在字符串前使用 @ 并将其写入多行,就像您在 SQL 编辑器中所做的那样。阅读起来会很简单。
【解决方案2】:

您可以对日期进行字符串插值并在此处添加单引号

$"'{parsed_start_date}'"

【讨论】:

  • 参数是唯一的答案,这也会导致SQL注入。
猜你喜欢
  • 1970-01-01
  • 2021-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-09
  • 2014-01-22
  • 1970-01-01
相关资源
最近更新 更多