我有一个查询正在检索结果的两列。我两次使用此查询,并将这两个查询与UNION ALL
放在一起,因为对于每条记录,应该有另一条记录,但是在两列中,我根据值预先设置了不同的值我其中一组设定的列之一。
我应该有一个将所有价格都设置为Debit
或Credit
的列,如果ExamType
为6,则应该在Credit
列中设置价格,如果ExamType
为2,则价格应在Debit
中设置。
如果我分别运行它们,则可以正常工作,但是一旦我使用union all
,就会收到数据类型错误消息。我将这些列设置为NULLS,但是所有内容都在Credit
列下,而Debit
列的值为空。我该如何解决?
带有短“不可见”字符串的示例:
Select StudentID, ExamDate, 2 AS ExamType, '232-442' AS Account,Amounts AS Debit, '' AS Credit
From TableA
UNION ALL
Select StudentID, ExamDate, 6 AS ExamType, '832-446' AS Account, Amounts AS Credit, '' AS Debit
From TableA
ORDER BY 1
带有NULL
Select StudentID, ExamDate, 2 AS ExamType, '232-442' AS Account,NULL AS Credit,Amounts AS Debit
From TableA
UNION ALL
Select StudentID, ExamDate, 6 AS ExamType, '832-446' AS Account, NULL AS Debit, Amounts AS Credit,
From TableA
ORDER BY 1
最终结果-应该如何:
StudentID ExamDate ExamType Account Debit Credit
1232111 8/9/2010 2 232-442 56.90
1232111 8/9/2010 6 832-446 56.90
4773923 7/5/2010 2 232-442 46.91
4773923 7/5/2010 6 832-446 46.91
答案 0 :(得分:1)
您似乎在UNION
上犯了一些错误。
阅读Martin Gruber的“基本SQL”或至少阅读Firebird(更为简要的文档):https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-select.html#fblangref25-dml-select-union
您的简化查询在这里:
Select StudentID, 2 AS ExamType, NULL AS Credit, Amounts AS Debit
From TableA
UNION ALL
Select StudentID, 6 AS ExamType, NULL AS Debit, Amounts AS Credit,
From TableA
ORDER BY 1
1)列命名和所需结果
Select ' ' AS Credit, Amounts AS Debit
From TableA
UNION ALL
Select ' ' AS Debit, Amounts AS Credit,
From TableA
您希望它会产生类似交叉检查的数据
Debit Credit
56.90
46.91
56.90
46.91
实际输出将是
Debit Credit
56.90
46.91
56.90
46.91
您必须阅读UNION
子句中的文档!
列的名称和数据类型仅与union
中的FIRST前导查询有关。所有后续查询的确会适应(或无法适应)已在其之前设置的名称和数据类型。对于第一个查询之后的所有查询,最重要的是它们的列的顺序。
由于查询#1中的列#4已被称为Credit
-查询#2中的列#4和第二个查询中的as Debit
仍然如此被丢弃。第二个查询和其他查询的列仅按其顺序映射到开头查询,而没有其他内容。
2)列数据类型-添加到名称问题中。
在阅读完上述内容并解决了名称问题之后,您可能会以类似以下内容(最小化的示例)结尾:
Select NULL AS Credit, Amounts AS Debit
From TableA
UNION ALL
Select Amounts, NULL -- no names here, they do not matter
From TableA
在这里,您最终将获得数据类型不匹配错误。为什么?因为-您在上面阅读过-类型是由LEADING查询设置的,因此第一列的类型为NULL
。当Firebird开始执行第二个查询时,它将获取一个非空数字Amounts
,并且您的前导查询会要求将数字转换为NULL。但这是不可能的。因此就是错误。
您要做的是在此查询中明确告诉您想要的Firebird WHICH列数据类型,而不管列值如何。
例如
Select StudentID, 2 AS ExamType,
CAST( NULL AS NUMERIC(10,2)) AS Credit,
Amounts AS Debit
From TableA
UNION ALL
Select StudentID, 6, Amounts, NULL
From TableA
3)排序-联合会以菊花链方式链接整个查询,其中可能包含非常不同的数据源和过滤条件。因此,排序很可能是在提取所有记录之后才进行的,这很可能是natural sorting
,而忽略了您可能在tableA
上拥有的所有索引,因此应该很慢,并且内存在大桌子上消费。
坦率地说,要提高大型查询的效率,最好将UNION
替换为EXECUTE BLOCK
或STORED PROCEDURE
之类的内容,就像几天前概述的那样:Display two unrelated select queries with no mutual fields in one firebird procedure
在小查询上,尽管提取后自然排序的额外负担很小,并且查询的简单性可能具有更大的权重。做出选择。
答案 1 :(得分:1)
在Firebird中,必须键入列,这是从基础列或文字值中推断出来的。对于UNION
,第一个查询将确定列数据类型及其名称。第二个(及后续)查询的列按位置必须具有相同的数据类型。
换句话说,您的查询
Select StudentID, ExamDate, 2 AS ExamType, '232-442' AS Account,Amounts AS Debit, '' AS Credit
From TableA
UNION ALL
Select StudentID, ExamDate, 6 AS ExamType, '832-446' AS Account, Amounts AS Credit, '' AS Debit
From TableA
此查询有两个不同的问题:
Debit
,第七列将称为Credit
。这意味着即使您在第二个查询中切换名称,值也不会,并且这些值仍会出现在Debit
列中。CHAR(1)
(对于第二个示例,则推断为SQL_NULL
),而不是数字类型。要解决此问题,您需要:
NULL
的值显式转换为适当的类型(例如DECIMAL(18,2)
)结果查询为
Select StudentID, ExamDate, 2 AS ExamType, '232-442' AS Account, Amounts AS Debit, CAST(NULL AS DECIMAL(18,2)) AS Credit
From TableA
UNION ALL
Select StudentID, ExamDate, 6 AS ExamType, '832-446' AS Account, NULL AS Debit, Amounts AS Credit
From TableA
我在第二个查询中保留了AS
子句,但它们仅用作文档:Firebird本身会忽略它们,而仅使用第一个查询中定义的标签。
但是我想知道您当前的方法是否正确:听起来更像是一个问题,要求在UNION ALL
表和某些成本/财务之间进行联接,而不是使用student
表。但是由于您的问题中缺少细节,因此很难确定。
我没有在答案中说明必要的顺序,请看一下Arioch'The的答案。