2

I've seen other similar questions and I have tried implementing many solutions, but to to no avail so far. This specific questions involves a little more complexity. What I need to do is create a table and join columns to the right side depending on certain criterion. It seems simple enough, but there are a few bumps that I am encountering.

The tables are as follows:

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

I want my final output to look like:

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

The "data" column is filled in using the table ADC_DATA_COLLECTION_DATA. The first instance of "data" would be the "data" field in ADC_DATA_COLLECTION_DATA where DATA_ELEMENT_NUMBER = 1. The second instance of "data" would be the "data" field in ADC_DATA_COLLECTION_DATA where DATA_ELEMENT_NUMBER = 2... And so on.

The furthest I have gotten is by using a join statement, except I have nulls in places I do not want them. The code I have used and the results are posted below. So far I only wrote code for the first two columns of data.

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

The result from this appears with null values which I do not want to have.

If you can offer an explicit solution using a join statement or a fix to this union approach, it would be much appreciated. Thank you in advance!

4

2 回答 2

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)相当常见的“数据透视表”hack。Oracle 也支持PIVOT查询,但我对它们不是很好。

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

于 2013-07-29T19:50:33.693 回答
1

我会为此使用枢轴:

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

于 2013-07-29T20:17:39.870 回答