【问题标题】:Order a query based on a field pointing to the same table根据指向同一个表的字段对查询进行排序
【发布时间】:2009-08-27 08:50:25
【问题描述】:

我有一个名为“句子”的表格,其中包含以下字段:

ID         <--- OK
NextID     <--- FK To ID
Text

如果我有以下记录:

*ID*            *NextID*          *Text*
1               12                The quick
3               40                jumps over
5               null              lazy dog.
12              3                 brown fox
40              5                 the

如果我知道序列的开头是 ID = 1 的记录,有没有办法根据 NextID 的序列对查询进行排序。和上面的例子一样,预期的结果应该是……

The quick
brown fox
jumps over
the
lazy dog.

我正在寻找 T-SQL 语句或以某种方式使用 Linq 执行此操作。提前致谢!

【问题讨论】:

  • 一个sql链表...有趣!
  • 如果使用 oracle 的任何人想要做同样的事情,我会提到 oracle 有“Connect By”子句,它可以非常简单地解决这个问题,并且适用于更复杂的树结构。

标签: sql-server database linq tsql


【解决方案1】:

试试这个:

declare @YourTable table (RowID int primary key, NextID int, TextValue varchar(50))

INSERT INTO @YourTable VALUES (1 , 12  ,'The quick')
INSERT INTO @YourTable VALUES (3 , 40  ,'jumps over')
INSERT INTO @YourTable VALUES (5 , null,'lazy dog.')
INSERT INTO @YourTable VALUES (12, 3   ,'brown fox')
INSERT INTO @YourTable VALUES (40, 5   ,'the')

;with cteview as (
SELECT * FROM @YourTable WHERE RowID=1
UNION ALL
SELECT y.* FROM @YourTable y
    INNER JOIN cteview   c ON y.RowID=c.NextID
) 
select * from cteview
OPTION (MAXRECURSION 9999) --go beyond default 100 levels of recursion to 9999 levels

输出:

RowID       NextID      TextValue
----------- ----------- --------------------------------------------------
1           12          The quick
12          3           brown fox
3           40          jumps over
40          5           the
5           NULL        lazy dog.

(5 row(s) affected)

【讨论】:

  • 这最多可以进行 100 次递归,然后您必须配置 SQL Server 以允许更高的递归深度。
  • 您不必更改服务器默认值 100。如果在 select * from cteview 之后添加 OPTION (MAXRECURSION n),其中n 可以在 0 到 32,767 级递归之间(零没有限制)
  • 这看起来很简洁,但我想知道是否可以将其转换为 LINQ 语句。
  • +1 非常聪明。我不知道这样的递归表达式是可能的
  • linq-to-sql 中的公用表表达式 (CTE)?:stackoverflow.com/questions/584841/…
【解决方案2】:

LINQ 答案:

table.OrderBy(sentence => sentence.NextID);

编辑:希望这次我回答正确:

class Sentence
{
    public int Id;
    public int? NextId;
    public string Text;
    public Sentence(int id, int? nextId, string text)
    {
        this.Id = id;
        this.NextId = nextId;
        this.Text = text;
    }
}

var Sentences = new [] {
    new Sentence(1, 12, "This quick"),
    new Sentence(3, 40, "jumps over"),
    new Sentence(5, null, "lazy dog."),
    new Sentence(12, 3, "brown fox"),
    new Sentence(40, 5, "the"),
};

Func<int?, string> GenerateSentence = null;
GenerateSentence = (id) => id.HasValue? Sentences
    .Where(s => s.Id == id.Value)
    .Select(s => s.Text + " " + GenerateSentence(s.NextId))
    .Single() : string.Empty;

Console.WriteLine(GenerateSentence(1));

【讨论】:

  • 这不会给你一个...懒狗的结果。棕狐快跳过去???
  • 使用这样的应用程序端解决方案,您必须返回整个表,然后将所有 id+nextID 重新组合在一起,否则您将不得不为每个 SELECT 访问数据库细分
  • @KM... 这就是我要避免的。每次都打数据库。
【解决方案3】:

如果您使用的是 LINQ to SQL/Entities,那么生成的 Sentence 类应该具有您提到的所有这些属性,以及外键对下一个句子(我们称之为 NextSentence)的实体引用。

那么你可以这样做:

Sentence s = Sentences.First();
StringBuilder sb = new StringBuilder();
do { sb.Append(s.Text); s = s.NextSentence; } while (s != null);

sb.ToString() 会为您解答。

【讨论】:

    猜你喜欢
    • 2012-10-10
    • 2015-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-09
    • 1970-01-01
    • 1970-01-01
    • 2020-08-31
    相关资源
    最近更新 更多