【问题标题】:Get rows which have different combinations of properties from another table从另一个表中获取具有不同属性组合的行
【发布时间】:2012-05-12 16:06:15
【问题描述】:

我在做什么:

我正在编写一个 C# 应用程序来帮助员工处理电子邮件。我有一个包含邮件的数据库(MS SQL Server 2008 Express)。一个表包含邮件本身(每一行都有 msgId、发件人、收件人、主题、正文等列),另一个表包含员工如何处理邮件的数据 - 每当电子邮件分配了某些属性时,都会有一个新行与属性保存到第二个表。第二个表包含列:msgId、forTeam、notForTeam、processedByTeam。每当员工将消息标记为与其团队相关时,就会在 forTeam 列中保存一行带有 TEAMXX 值的行。每当员工对电子邮件执行其他操作时,都会将带有 TEAMXX 值的行保存在 processesByTeam 列中。

我正在尝试接收具有以下值的电子邮件:
forTeam: 'TEAM01'
notForTeam:一切都不同于“TEAM01”
processesByTeam:与“TEAM01”不同的所有内容

我使用 MailAssignments 表在 Mails 表上执行 LEFT JOIN,然后在 WHERE 之后放置上述条件。结果应该显示已分配给 TEAM01 但尚未由该团队的员工处理的消息。



问题:

我无法让 SQL 查询正常工作。条件的任何组合都将返回额外的行(例如,当我想省略这些时,使用属性 notForTeam='TEAM01'!)或给我一个错误,即日期时间由于某种原因格式不正确(我正在按接收时间对电子邮件进行排序)。

查询示例:

SELECT TOP 30 Mails.* 
FROM Mails 
LEFT JOIN MailAssignments 
ON Mails.msgId = MailAssignments.msgId 
WHERE
(MailAssignments.forTeam='TEAM01') 
AND (MailAssignments.notForTeam<>'TEAM01' OR MailAssignments.notForTeam IS NULL) 
AND (MailAssignments.processedByTeam<>'TEAM01' OR MailAssignments.processedByTeam IS NULL)
ORDER BY Mails.sortingTime DESC

即使我将 WHERE 之后(以及 ORDER BY 之前)的条件减少到 (MailAssignments.notForTeam&lt;&gt;'TEAM01') 进行测试,由于某种原因,我仍然会收到错误。

我错过了什么或做错了什么?



更新:

似乎(MailAssignments.notForTeam&lt;&gt;'TEAM01') 以某种方式导致了问题。其他一切正常(等号也可以:MailAssignments.notForTeam='TEAM01')但是当我添加 notForTeam&lt;&gt; 条件时,我得到了不正确的日期时间错误(WTF?:/)

System.Data.SqlTypes.SqlTypeException:SqlDateTime 溢出。必须在 1753 年 1 月 1 日凌晨 12:00:00 到 9999 年 12 月 31 日晚上 11:59:59 之间。



更新 - 示例:

table with mails ("Mails"):
msgId sender  subject body  received (sortingTime)
53    x@x.com test    test  2012-05-11 11:00
54    b@b.com test2   test2 2012-05-10 10:00
55    h@h.com blah    blah  2012-05-11 12:00
56    t@t.com dfgg    dfgg  2012-05-11 12:30


table with assignments ("MailAssignments"):
msgId forTeam notForTeam  processedByTeam
54    null    TEAM02      null            - this means TEAM02 hid the mail from their view
54    TEAM01  null        null            - this means TEAM01 assigned the mail to them
54    null    null        TEAM01          - TEAM01 has processed the mail

53    TEAM01  null        null            - invisible to other teams
53    null    TEAM01      null            - invisible for TEAM01 (and also for others because of the above)

56    TEAM01  null        null
56    null    null        TEAM01          - mail processed by TEAM01

55    TEAM02  null        null            - assigned to TEAM02 but not processed yet


Now, I want my C# app to have a view which will display mails as "This Team's", ie.:
1. mail 54 was first hidden for TEAM02 - should be invisible for them
2. mail 54 was assigned to TEAM01 - should be now visible for them in "This Team's" view
3. mail 54 was processed by TEAM01 - should be now invisible in "This Team's" view

4. mail 53 was assigned to TEAM01 - should visible in their "This Team's" view (and ONLY for them)
5. mail 53 was hidden for TEAM01 - should be invisible to TEAM01 (and for anyone else because of prev. action)

6. mail 56 was assigned to TEAM01 - should be now visible only to TEAM01 in "This Team's"
7. mail 56 was processed by TEAM01 - should be now invisible for TEAM01 in "This Team's"

So, with the present data in both tables, finally, TEAM02 for example should see in their "This Team's" view only:
mail 55

【问题讨论】:

  • 请不要在标题前加上“C#/T-SQL:”之类的前缀。这就是标签的用途。
  • NotForTeam 列的类型是什么?
  • 另外,尝试在您的查询分析器中运行查询并判断错误是否在那里发生
  • notForTeam 列是 char(10)
  • 在服务器管理工​​作室中执行的查询似乎返回了正确的结果

标签: c# sql-server-2008 tsql


【解决方案1】:
Select TOP 30 *
From Mails As M
Where Exists    (
                Select 1
                From MailAssignments As MA1
                Where MA1.msgid = M.msgid
                    And MA1.forTeam = 'TEAM01'
                Except
                Select 1
                From MailAssignments As MA1
                Where MA1.msgid = M.msgid
                    And ( MA1.processedByTeam = 'TEAM01' 
                         Or MA1.notForTeam = 'TEAM01' )
                )
Order By M.received Desc

SQL Fiddle 版本。

拥有示例数据和架构会让世界变得与众不同。错过的是每个Mails 行有多个MailAssignments 行。因此,当您说要排除 notForTeam = 'TEAM01' 所在的行时,真正的意思是排除具有该值的任何关联 msgid。我已经更新了我的查询以适应该请求。您可能会怀疑Except 子句会消除第二个查询中存在于第一个查询中的任何匹配值。由于我在两个查询中都使用了常量,如果第二个查询返回给定 msgid 的任何行,它将使整个 Exists 查询不返回任何行并排除 msg。

也就是说,TEAM01 没有任何行,因为:

MsgId = 54 is excluded because according to Rule #3, messages 
    that were processed by the team should be excluded.
MsgId = 53 is excluded because notForTeam = 'TEAM01' (Rule #5)
MsgId = 56 is excluded because processedBy = 'TEAM01' (Rule #7)
MsgId = 55 is excluded because forTeam = 'TEAM02'

【讨论】:

  • @ValCool - 我添加了一个 SQL Fiddle 示例,使用上述查询可以正常工作。
  • @ValCool - 如果有问题的查询返回正确的结果,这现在更像是一个巫术。需要检查的一些事项: 1. C# 应用程序连接到您在 SSMS 中运行成功测试的同一数据库。 2. 错误数据类型的值未传递给 Command 对象中的参数之一。 3. 如果实际查询中存在未引发错误的 UDF。我的建议是注释掉查询的某些部分,直到您遇到引发错误的行。
  • @ValCool - 没有其他问题可以查询吗?即,唯一通过的正是我在结果中显示的内容?我要解决的问题是,错误很可能是一个红鲱鱼,而其他东西有日期时间转换问题。
  • 好的,我创建了一个单独的字符串变量来保存查询并且仅用于获取数据,并将您的代码粘贴到其中。我收到错误:System.Data.SqlClient.SqlException:关键字“存在”附近的语法不正确。 'MA1' 附近的语法不正确。 所有其他查询仍然可以正常工作!
  • @ValCool - 我需要看看你是如何在 C# 中执行查询的。您知道查询在从 SSMS 运行时有效,因此很明显,从 C# 执行查询的方式出现了问题。执行之前的 SQL 文本是什么(参数和所有)?
【解决方案2】:

试试:

WHERE
MailAssignments.forTeam='TEAM01'
AND MailAssignments.notForTeam<>'TEAM01'
AND MailAssignments.processedByTeam<>'TEAM01'
ORDER BY Mails.sortingTime DESC

这应该可以解决问题

【讨论】:

  • 但这很可能还会返回在forTeam 列中没有任何值的邮件,即。尚未与任何团队相关联。我希望在我的查询中显示已分配给指定团队的邮件(并且可能已被其他团队标记为“不适合他们的团队”),但还没有被团队处理
  • 我关注了你的问题:forTeam: 'TEAM01' or nothing, notForTeam: 一切都不同于 'TEAM01',processedByTeam: 一切都不同于'TEAM01'
  • 是的,你是对的。我的错。经过多次尝试修复它,我迷失在代码中。我已经更正了问题
  • 但是您的查询不会跳过 notForTeam 和 processesByTeam 属性中具有空值的行吗?
  • 我已经试过你的代码了。它还向我抛出了关于该死的日期时间错误的错误,WTF 是 SQL Server 错误吗? D:
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-05
  • 2016-08-18
  • 1970-01-01
相关资源
最近更新 更多