SQL 表达式中非常大的 IN 子句

Very huge IN clause in SQL expression

假设我有一个产品 table 有 100 万条记录(是的,我有 100 万条产品!)。

此产品 table 有一个参考字符串字段。

有些人想要导出除某些产品之外的所有产品的 csv 文件。

我们知道要排除的产品的参考资料。它们存储在 csv 文件中。

这是我构建的查询:

SELECT ... FROM products WHERE reference NOT IN ('ref1','ref2','.....')

排除少于 100 个引用时一切正常。

如果我要排除的参考文献超过 10000 条,我该怎么办? sql 查询非常大。

我试过 mysql、postgre 和 sql 服务器。同样的问题。

谢谢

将 CSV 文件加载到 table 中,reference 作为主键。

然后使用not exists:

SELECT ...
FROM products p
WHERE NOT EXISTS (SELECT 1
                  FROM csv_table c
                  WHERE c.reference = p.reference
                 );

当然,创建 CSV table 的逻辑取决于数据库。但是,任何可以使用索引的数据库都应该能够对此进行优化。

如果您可以对 table 进行更改;您可以有一个额外的列作为排除(位字段)并在需要排除时更新为 1,如果不需要则保持为 0。 不要维护 CSV 文件,而是将排除数据存储在 table 中,并在 运行 查询之前更新主 table。

那么在查询的时候,就用那一列作为筛选即可。

您可以在 SQL 服务器上使用 table 值参数。

查询如下所示:

SELECT *
FROM products AS P
LEFT JOIN @exludedProducts AS EP ON EP.reference = P.reference
WHERE P.reference IS NULL

您需要像这样声明 table 值类型(检查类型以匹配您的 table):

CREATE TYPE dbo.ProductReferenceTvp AS TABLE 
(
    reference VARCHAR(10) NOT NULL
)

您的 .Net 代码可能如下所示:

public void GetProducts(IEnumerable<string> excludedProducts)
{
    StringBuilder sb = new StringBuilder();
            
    sb.AppendLine(" SELECT * ");
    sb.AppendLine(" FROM products AS P ");
    sb.AppendLine(" LEFT JOIN @exludedProducts AS EP ON EP.reference = P.reference ");
    sb.AppendLine(" WHERE P.reference IS NULL ");
            
    using (var cn = new SqlConnection(ConnectionString))
    {
        using (SqlCommand cmd = new SqlCommand(sb.ToString(), cn))
        {
            var pExcludedProducts = GetTvp("@exludedProducts", excludedProducts.Distinct());
            cmd.Parameters.Add(pExcludedProducts);

            DataSet ds = new DataSet();
            new SqlDataAdapter(cmd).Fill(ds);
            Print(ds);
        }
    }
}

private SqlParameter GetTvp(string name, IEnumerable<string> excludedProducts)
{
    var dt = new DataTable();
    dt.Columns.Add("reference", typeof(String));
    foreach (var product in excludedProducts)
    {
        dt.Rows.Add(product);
    }
    var p = new SqlParameter(name, dt);
    p.SqlDbType = SqlDbType.Structured;
    p.TypeName = "dbo.ProductReferenceTvp";
    return p;
}