高级SQL选择和联合语句

时间:2013-07-29 19:09:55

标签: sql vb.net oracle oracle-sqldeveloper

我见过其他类似的问题,我尝试过实施多种解决方案,但到目前为止无济于事。这个具体问题涉及更复杂一点。我需要做的是根据特定标准创建一个表并将列连接到右侧。这似乎很简单,但我遇到了一些障碍。

表格如下:

ADC_DATA_COLLECTION_HEADER

(PK)Transaction_ID | BEMSID | DEVICE | TIMESTAMP | CONFIG_NAME

ADC_DATA_COLLECTION_APPS

(FK)CONFIG_NAME | NUM_DATA_ELEMENTS | DATA_ELEMENT1 | DATA_ELEMENT2 | DATA_ELEMENT3 | DATA_ELEMENT4


ADC_DATA_COLLECTION_DATA

(FK)TRANSACTION_ID | DATA_ELEMENT_NUMBER | DATA

我希望我的最终输出看起来像:

TRANSACTION_ID | DEVICE | CONFIG_NAME | DATA | DATA | DATA | DATA

使用表ADC_DATA_COLLECTION_DATA填写“data”列。 “data”的第一个实例是ADC_DATA_COLLECTION_DATA中的“data”字段,其中DATA_ELEMENT_NUMBER = 1.“data”的第二个实例是ADC_DATA_COLLECTION_DATA中的“data”字段,其中DATA_ELEMENT_NUMBER = 2 ......依此类推。

我得到的最远的是使用连接语句,除了我在不想要它们的地方有空值。我使用的代码和结果发布在下面。到目前为止,我只为前两列数据编写了代码。

SELECT 
ADC_Data_Collection_header.BEMSID, 
ADC_Data_Collection_header.DEVICE, 
ADC_Data_Collection_header.CONFIG_NAME, 
null AS locationlabel, 
null AS partno 
/*null AS partno2, 
null AS DE4, 
null AS DE5, 
null AS DE6 */
FROM 
ADC_Data_Collection_header, 
ADC_Data_Collection_apps, 
ADC_Data_Collection_data 
WHERE 
ADC_Data_Collection_header.CONFIG_NAME = 'mobileScanning' 
AND ADC_Data_Collection_header.BEMSID = '2386531' 
AND ADC_Data_Collection_header.CONFIG_NAME = ADC_Data_Collection_apps.CONFIG_NAME 
AND (TO_DATE('7/19/2013','MM/DD/YYYY') <= timestamp AND TO_DATE('7/27/2013','MM/DD/YYYY') >= timestamp) 
AND ADC_DATA_COLLECTION_HEADER.transaction_ID = ADC_DATA_COLLECTION_DATA.Transaction_ID

UNION
SELECT
null as BEMSID, 
null as DEVICE, 
null as CONFIG_NAME,
ADC_Data_Collection_DATA.DATA AS locationlabel, 
null as partno
FROM 
ADC_DATA_COLLECTION_DATA,
ADC_Data_Collection_header, 
ADC_Data_Collection_apps
WHERE 
ADC_DATA_COLLECTION_DATA.DATA_ELEMENT_NUMBER = 3 
AND ADC_Data_Collection_header.CONFIG_NAME = 'mobileScanning' 
AND (TO_DATE('7/19/2013','MM/DD/YYYY') <= timestamp AND TO_DATE('7/27/2013','MM/DD/YYYY') >= timestamp) 
AND ADC_DATA_COLLECTION_HEADER.transaction_ID = ADC_DATA_COLLECTION_DATA.Transaction_ID

UNION
SELECT
null as BEMSID, 
null as DEVICE, 
null as CONFIG_NAME,
null as locationlabel,
ADC_Data_Collection_DATA.DATA AS partno
FROM 
ADC_DATA_COLLECTION_DATA,
ADC_Data_Collection_header, 
ADC_Data_Collection_apps
WHERE 
ADC_DATA_COLLECTION_DATA.DATA_ELEMENT_NUMBER = 4 
AND ADC_Data_Collection_header.CONFIG_NAME = 'mobileScanning' 
AND (TO_DATE('7/19/2013','MM/DD/YYYY') <= timestamp AND TO_DATE('7/27/2013','MM/DD/YYYY') >= timestamp) 
AND ADC_DATA_COLLECTION_HEADER.transaction_ID = ADC_DATA_COLLECTION_DATA.Transaction_ID

此结果显示为空值,我不想拥有。

如果您可以使用连接语句或修复此联合方法提供显式解决方案,那将非常感激。提前谢谢!

2 个答案:

答案 0 :(得分:3)

UNION为您提供了额外的行,因此它不适合这种情况。

这是一个仅使用ADC_DATA_COLLECTION_DATA表格的缩写版本;您应该能够将其合并到您的查询中:

SELECT 
  Transaction_ID,
  MAX(CASE WHEN Data_Element_Number = 1 THEN Data END) AS Data1,
  MAX(CASE WHEN Data_Element_Number = 2 THEN Data END) AS Data2,
  MAX(CASE WHEN Data_Element_Number = 3 THEN Data END) AS Data3,
  MAX(CASE WHEN Data_Element_Number = 4 THEN Data END) AS Data4
FROM ADC_DATA_COLLECTION_DATA
GROUP BY Transaction_ID

对于Oracle(以及MySQL和SQL Server)来说,这是一个相当常见的“数据透视表”攻击。 Oracle也支持PIVOT queries,但我对他们不太满意。

请注意,将最终查询与DeviceConfig_Name列放在一起后,您需要将这些列添加到GROUP BY

答案 1 :(得分:1)

我会使用pivot:

select
    h.transaction_id,
    h.device,
    h.config_name,
    d.data1,
    d.data2,
    d.data3,
    d.data4
from
    ADC_DATA_COLLECTION_HEADER h
    inner join (
      select *
      from ADC_DATA_COLLECTION_DATA
      pivot
      (
          max(data)
          for data_element_number in (1 as data1, 2 as data2, 3 as data3, 4 as data4)
      )
    ) d
        on d.transaction_id = h.transaction_id
where
    (TO_DATE('7/19/2013','MM/DD/YYYY') <= timestamp AND TO_DATE('7/27/2013','MM/DD/YYYY') >= timestamp);

我将一个示例SQL Fiddle放在一起:http://www.sqlfiddle.com/#!4/fe1c94/9/0