Home > Net >  SQL table join - 1 column data split to 2 columns depending on another column
SQL table join - 1 column data split to 2 columns depending on another column

Time:06-13

I have some data in x2 tables (d and i) that I want to join and split 1 table's data (i) in to 2 columns depending on data in another column of table i.

Example of the data I have is (I have cut out multiple fields as both tables hold a lot more data than I require):

Table: INFO

isite inum idet idata
332 1 20 001122334455
332 2 20 112233445566
332 3 20 223344556677
332 1 22 Samsung
332 2 22 Sony
332 3 22 LG

Table: DEVICE

dsite dnum dname
332 1 abc123
332 2 def456
332 3 ghi789

What I want to do is join the 2 tables and depending on the value of i.det determines which column header i.data goes in to. So my query stands as:

SELECT d.dname as Unit_name, i.idata as Unit_Data FROM DEVICE d 
LEFT JOIN INFO i 
    ON d.dsite = i.isite AND d.dnum = i.inum 
WHERE (i.idet = 20 OR i.idet = 22)
AND d.dsite = 332;

Which will give me the data listing the dname twice with each piece of data as follows:

Unit_name Unit_data
abc123 001122334455
abc123 Samsung
def456 112233445566
def456 Sony
ghi789 223344556677
ghi789 LG

My desired output though would be as follows:

Unit_name Unit_MAC Unit_Manufacturer
abc123 00112233445566 Samsung
def456 11223344556677 Sony
ghi789 22334455667788 LG

So basically when idet = 20 the idata is joined under Unit_MAC for the matching isite and inum, and when idet = 22 the idata is joined under the Unit_Manufacturer for the matching isite and inum.

Hopefully what I have put has made sense, I'm sure what I want is probably very simple but I can't wrap my head round what my query needs to be at the moment! Thanks for any pointers in advance!!

CodePudding user response:

Use conditional aggregation in your query:

SELECT d.dname AS Unit_name, 
       MAX(CASE WHEN i.idet = 20 THEN i.idata END) AS Unit_MAC,
       MAX(CASE WHEN i.idet = 22 THEN i.idata END) AS Unit_Manufacturer
FROM DEVICE d LEFT JOIN INFO i 
ON d.dsite = i.isite AND d.dnum = i.inum 
WHERE d.dsite = 332 AND (i.idet = 20 OR i.idet = 22)
GROUP BY d.dname;

I assume that dname is unique in DEVICE.

See the demo.

CodePudding user response:

SQL Fiddle (Assuming MSSQL)

DML Query ( a bit long-winded using CTES):

/*Resolve the mac address of devices:
infonumbers => CTE*/
WITH infonumbers AS (
  SELECT
    isite,
    inum, 
    idet,
    idata AS unit_mac
  FROM
    INFO
  WHERE
    ISNUMERIC(idata) = 1
 ),

/*Resolve the device manufacturers devices:
infostrings => CTE*/
 infostrings AS (
  SELECT
    isite,
    inum, 
    idet,
    idata AS unit_manufacturer
  FROM
    INFO
  WHERE
    ISNUMERIC(idata) = 0
 )

/*Join together with devices to resolve device name,
mac address, and manufacturer: TABLE => stdout(console)*/
  SELECT 
    d.dname,
    ino.unit_mac,
    istr.unit_manufacturer
   FROM 
     infonumbers ino
   INNER JOIN
     infostrings istr
   ON
     ino.isite = istr.isite
   AND
     ino.inum = istr.inum
   LEFT OUTER JOIN
     DEVICE d
   ON 
     ino.isite = d.dsite 
   AND 
     ino.inum = d.dnum 

(DDL) Data:

CREATE TABLE INFO (
  isite INTEGER NOT NULL,
  inum INTEGER NOT NULL,
  idet INTEGER NOT NULL,
  idata NVARCHAR(MAX) NOT NULL
);

INSERT INTO INFO 
VALUES 
  (332, 1,  20, '001122334455'),
  (332, 2,  20, '112233445566'),
  (332, 3,  20, '223344556677'),
  (332, 1,  22, 'Samsung'),
  (332, 2,  22, 'Sony'),
  (332, 3, 22, 'LG')
  
CREATE TABLE DEVICE (
  dsite INTEGER NOT NULL,
  dnum INTEGER NOT NULL,
  dname NVARCHAR(MAX) NOT NULL,
);

INSERT INTO DEVICE
VALUES
  (332, 1, 'abc123'),
  (332, 2, 'def456'),
  (332, 3, 'ghi789')
  • Related