【问题标题】:Convert linq with All to SQL将 linq with All 转换为 SQL
【发布时间】:2013-03-07 02:39:42
【问题描述】:

我有表 A、B 和 C

B 与 A 是多对一的

我想找到所有 A,其中 C 是 B 的完整子集。

以下 LINQ 查询(伪代码)代表我想要得到的。

class A
{
    public B[] Bs { get; set; }
}

class B
{
    public string Text { get; set; }
}

class C
{
    public string Text { get; set; }
}

private static IEnumerable<A> Search(C[] C, A[] A)
{
    return from a in A
            where C.All(c => a.Bs.Any(b => SomeCondition(b, c)))
            select a;
}

private static bool SomeCondition(B b, C c)
{
    //There we comparing B and C
    throw new NotImplementedException();
}

我有以下表结构

A ( a_ID INT PRIMARY KEY )
B ( b_ID INT PRIMARY KEY, a_ID INT, Text NVARCHAR(MAX) )
C ( c_ID INT PRIMARY KEY, Text NVARCHAR(MAX) )

我需要得到 ALL A,其中 B 匹配所有 C。

例子

A | a_ID |
  | 1    |
  | 2    |
  | 3    |

B | b_ID | a_ID | Text  |
  | 1    | 1    | Cat   |
  | 2    | 1    | Dog   |
  | 3    | 1    | Rabbit| 
  | 4    | 2    | Cat   | 
  | 5    | 2    | Cat   | -- B can contain duplicates
  | 6    | 2    | Rabbit|

C | c_ID | Text |
  | 1    | Cat  |
  | 2    | Dog  |

输出

| a_ID |
| 1    |

【问题讨论】:

  • @tmack 这是一个伪代码。
  • 信息不足,无法理解问题。如果它会编译,它可能会。
  • 你能提供表格的 DDL 和想要的输出吗?
  • 您使用的是什么 linq 提供程序? LINQ 2 Sql?英孚?
  • @andri 我没有使用 linq 提供程序,它是我需要用 SQL 编写的伪代码

标签: sql linq tsql


【解决方案1】:

UPDATED3:计算不同的 c_id

SELECT b.a_id
  FROM b
  JOIN c ON b.Text = c.Text
GROUP BY b.a_id
HAVING COUNT(distinct c.c_id) = (SELECT COUNT(*) FROM C)

输出:

| A_ID |
--------
|    1 |

这是一个sqlfiddle example

【讨论】:

  • 它将在 C 中的任何 B 中选择 A。不是全部。
  • 谢谢@peterm 有没有办法避免计数(*)?
  • 其实这里不需要加入A
  • 足够公平的 JOIN 与 A 是多余的。更新了答案。不,在我的查询版本中,您无法避免 COUNT。但是它执行一次并且速度很快。顺便说一句,如果C.TextNULLable,那么您需要使用SELECT COUNT(Text) FROM C
  • 由 COUNT(distinct c.c_id) 修复
【解决方案2】:

好的,我知道怎么弄了。

假设x=&gt;x.All(e =&gt; predicate(e))可以转换为x=&gt;!x.Any(e =&gt; !predicate(e))

我们可以将原来的表达式转换为下面的表达式

from a in A
where !C.Any(c => !a.Bs.Any(b => SomeCondition(b, c)))
select a;

任何可以使用exists关键字转换为SQL

我会假设SomeCondition 是相等的

首先将!a.Bs.Any(b =&gt; SomeCondition(b, c))转换为SQL

NOT EXISTS (
    SELECT 1 FROM B b
        WHERE a.a_id = b.a_id -- a will be added later
          AND c.Text = b.Text -- c will be added later
)

接下来转换!C.Any(c =&gt; !a.Bs.Any(b =&gt; SomeCondition(b, c)))

NOT EXISTS (
    SELECT 1 FROM C c
    WHERE NOT EXISTS (
        SELECT 1 FROM B b
        WHERE a.a_id = b.a_id -- a will be added later
          AND c.Text = b.Text
    )
)

最后是整个表达式

SELECT * FROM A a
WHERE NOT EXISTS (
    SELECT 1 FROM C c
    WHERE NOT EXISTS (
        SELECT 1 FROM B b
        WHERE a.a_id = b.a_id
          AND c.Text = b.Text
    )
)

现在我们可以做一些优化

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多