繁体   English   中英

MySQL IN子句:当我多次使用相同的值时,如何获得多行?

[英]MySQL IN clause: How can I get multiple rows when I use a same value multiple times?

我正在Visual Studio中编写C#Windows窗体应用程序,我正在尝试获取有关产品价格的数据以及用户将产品从我的本地MySQL数据库添加到其购物清单中的数量到List(int)。

我的工作如下:

如果用户已将产品添加到他们的购物清单4次,我将产品的条形码添加4次到我的列表(int)。

这是有效的,但当我用String.Join() - 方法将List的所有项目读入我的查询的IN子句并执行它时,它只返回一行,而IN运算符具有多次使用相同的条形码。

以下是我如何向我的List(int)添加条形码

int count = 0;
List<int> barcodes = new List<int>();
MySqlCommand cmd = new MySqlCommand("SELECT product_barcode, amount FROM shopping_list_items WHERE shopping_list_id = " + current_shoppingListID + ";", db.connection);
cmd.ExecuteNonQuery();
var reader = cmd.ExecuteReader();

while (reader.Read())
{
    do
    {
        barcodes.Add(Int32.Parse(reader["product_barcode"].ToString()));
        count++;
    } while (count < Int32.Parse(reader["amount"].ToString()));
}

reader.Close();

这就是我执行查询并将值分配给变量的方式:

MySqlCommand cmdSum = new MySqlCommand("SELECT sum(price) AS 'total', supermarket_id FROM prices WHERE barcode IN (" + String.Join(", ", barcodes) + ") GROUP BY supermarket_id;", db.connection);
cmdSum.ExecuteNonQuery();
var readerSum = cmdSum.ExecuteReader();

while (readerSum.Read())
{
    switch (double.Parse(readerSum["supermarket_id"].ToString()))
    {
        case 1:
            sumSupermarket1 = double.Parse(readerSum["total"].ToString());
            break;

        case 2:
            sumSupermarket2 = double.Parse(readerSum["total"].ToString());
            break;

        case 3:
            sumSupermarket3 = double.Parse(readerSum["total"].ToString());
            break;
     }
}

简化查询只是为了简化它可能如下所示:

SELECT name FROM products WHERE barcode IN (13495, 13495, 13495);

如果以上是我的查询,那么我希望它返回3相同的行。

所以我现在的问题是,如果我在MySQL查询的IN子句中多次使用相同的值,我怎样才能获得多行?

问:如果在MySQL查询的IN子句中多次使用相同的值,我怎样才能获得多行?

答:我们没有。 这不是IN ()工作原理。

注意

WHERE foo IN ('fee','fi','fi','fi')` 

是简写

WHERE ( foo = 'fee'
     OR foo = 'fi'
     OR foo = 'fi'
     OR foo = 'fi'
      )

了解这里发生的事情。 MySQL将检查每一行,并检查每一行,以查看此条件是否返回TRUE。 如果行满足条件,则返回行。 否则不返回该行。

foo值为'fi'满足多个条件并不重要。 所有MySQL关心的是,parens中的条件最终评估为TRUE。

作为说明,请考虑:

  WHERE ( t.picked_by     = 'peter piper'
       OR t.picked_amount = 'peck'
       OR t.name          LIKE '%pickled%'
       OR t.name          LIKE '%pepper%'
        )

可能有一行满足这些条件中的每一个。 WHERE子句只询问整个条件是否为TRUE。 如果是,请返回该行。 如果没有,则排除该行。 我们不会获得一行的四个副本,因为满足多个条件。


那么我们如何得到一个具有多行副本的集合呢?

作为一种可能的选择,我们可以使用单独的SELECT语句并将结果与UNION ALL集合运算符组合。 像这样的东西:

SELECT p1.name FROM product p1 WHERE p1.barcode IN (13495)
UNION ALL
SELECT p2.name FROM product p2 WHERE p2.barcode IN (13495)
UNION ALL
SELECT p3.name FROM product p3 WHERE p3.barcode IN (13495)

请注意,此查询的结果与原始查询的结果明显不同。

还有其他查询模式可以返回等效集。


跟进

如果不了解用例,规范,我只是在猜测我们试图实现的目标。 基于代码中显示的两个查询(遵循我们在代码中看到的易受SQL注入攻击的常见模式),

购物清单:

SELECT i.product_barcode
     , i.amount
  FROM shopping_list_item i
 WHERE i.shopping_list_id = :id

amountamount 这是订购的数量吗? 我们希望这个问题的两个罐,或磅的呢? 似乎我们希望将单价乘以订购数量以获得成本。 (两个罐子的成本是一个罐子的两倍。)

如果我们所追求的是来自多个商店的购物清单上商品的总成本,我们可以这样做:

SELECT SUM(p.price * s.amount)  AS `total`
     , p.supermarket_id 
  FROM ( SELECT i.product_barcode
              , i.amount
           FROM shopping_list_item i 
          WHERE i.shopping_list_id = :id
       ) s
  JOIN price p
    ON p.barcode = s.product_barcode
 GROUP
    BY p.supermarket_id

请注意,如果特定的product_barcode不适用于特定的supermarket_id ,则列表中的该项目将从总数中排除,即我们可以获得较低的总数,因为超市中没有列出所有内容。

为了提高性能,我们可以消除内联视图,并像这样编写查询:

SELECT SUM(p.price * i.amount)  AS `total`
     , p.supermarket_id
  FROM shopping_list_item i
  JOIN price p
    ON p.barcode = i.product_barcode
 WHERE i.shopping_list_id = :id
 GROUP
    BY p.supermarket_id

如果我们必须通过购物清单查询,然后使用其中的行来创建第二个查询,我们可以形成如下所示的查询:

SELECT SUM(p.price * i.amount) AS `total`
     , p.supermarket_id 
  FROM ( -- shopping_list here
         SELECT '13495' AS product_barcode, '1'+0 AS amount 
         UNION ALL SELECT '13495', '1'+0
         UNION ALL SELECT '13495', '1'+0
         UNION ALL SELECT '12222', '2'+0
         UNION ALL SELECT '15555', '5'+0
         -- end shopping_list
       ) i
   JOIN price p
     ON p.barcode = i.product_barcode
  WHERE i.shopping_list_id = :id
  GROUP
     BY p.supermarket_id

您可能最好调查LINQ to SQL而不是使用直接SQL和注入。

您可以使用内联表连接来完成所需的操作:

"SELECT sum(price) AS 'total', supermarket_id
 FROM (select "+barcodes[0]+"as bc union all select "+String.Join(" union all select ", barcodes.Skip(1).ToArray())+") w
 JOIN prices p ON p.barcode = w.bc
 GROUP BY supermarket_id;"

注意:如果可以使用内联表别名命名列(我无法测试),则可以简化内联表生成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM