合并所有不同的列

时间:2018-08-16 01:38:10

标签: sql firebird union-all

我有一个查询正在检索结果的两列。我两次使用此查询,并将这两个查询与UNION ALL放在一起,因为对于每条记录,应该有另一条记录,但是在两列中,我根据值预先设置了不同的值我其中一组设定的列之一。

我应该有一个将所有价格都设置为DebitCredit的列,如果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 

2 个答案:

答案 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 BLOCKSTORED 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

此查询有两个不同的问题:

  1. 第六列将称为Debit,第七列将称为Credit。这意味着即使您在第二个查询中切换名称,值也不会,并且这些值仍会出现在Debit列中。
  2. 第七列的数据类型将推断为CHAR(1)(对于第二个示例,则推断为SQL_NULL),而不是数字类型。

要解决此问题,您需要:

  1. 交换第二个查询中的列
  2. 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的答案。