简体   繁体   中英

OracleSQL: How do I add a specific AND is not null OR is not null to my query

Backstory :

  • I have three tables I'm working with. A directory table (directory), an general attribute table (attribute1table) and a specific attribute table (attribute2table). The general attribute tables hold attribute names (ex. Last Name) under attribute id's (attrid = 2). The specific attribute table holds specific data for these attributes (ex. Doe).
  • I needed to transpose rows to columns. I had tried using pivot, and max(decode) before but all options gave me the wrong string value- so I used a sub select within the select statement. This worked well- it did transpose the rows into columns but gave me a bunch of null values. See query at the bottom for steps.
  • Then I added in a general 'stringval IS NOT NULL' to eliminate any of the other attribute1table.attrid's (ex. 4, 5, 6). This worked.

This is the output I was getting at this point. The ? are null values.

Name    DataID    LastName    FirstName
File10  1290      ?           Jane
File10  1290      Doe         ?
  • Then I wanted to add in a specification. Essentially to include the values where LastName is not null OR FirstName is not null. I found that someone had recommended doing this in a previous question albeit their situation was different. Eliminating specific null values in sql select

I was able to include one statement or the other but could not add in both. Instead of getting an error I just got a horrifically long run time with no foreseeable result (note that I am using software which lets you input oracle queries within the interface to query the database). It works if I run the query up until the ** (see code) but as soon as I add in the OR condition, it doesn't work anymore. I think this is because I have multiple WHERE conditions. In all cases I want the directory ID and general stringval conditions to apply but I want to have a third condition where either lastname is not null or first name is not null. I'm not sure if I'm missing something obvious- please help?

Here is my current query:

SELECT directory.name, directory.dataid,
(SELECT max(stringval) FROM attribute2table WHERE attribute1table.attrid = 2) as LastName,
(SELECT max(stringval) FROM attribute2table WHERE attribute1table.attrid = 3) as FirstName

FROM attribute2table
JOIN directory ON directory.dataid = attribute2table.id
JOIN attribute1table ON attribute1table.id = directory.dataid
WHERE directory.dataid = 1290
AND stringval IS NOT NULL
AND (SELECT max(valstr) FROM attribute1table WHERE attribute1table.attrid = 2) IS NOT NULL
**OR (SELECT max(valstr) FROM attribute1table WHERE attribute1table.attrid = 3) IS NOT NULL**

Basically I just need to get rid of the null values and want my table to look like....

Name      DataID    LastName    FirstName
File10    1290      Doe         Jane

This appears to be a parenthesization issue. If I understand the issue, you need to put the two IS NOT NULL conditions in parentheses:

SELECT directory.name,
       directory.dataid, 
       m2.LastName, 
       m3.FirstName
  FROM attribute2table
  INNER JOIN directory
    ON directory.dataid = attribute2table.id
  INNER JOIN attribute1table
    ON attribute1table.id = directory.dataid
  LEFT OUTER JOIN (SELECT max(valstr) AS LASTNAME
                     FROM attribute1table
                     WHERE attribute1table.attrid = 2) m2
    ON 1 = 1
  LEFT OUTER JOIN (SELECT max(valstr) AS FIRSTNAME
                     FROM attribute1table
                     WHERE attribute1table.attrid = 3) m3
    ON 1 = 1
  WHERE directory.dataid = 1290 AND
        stringval IS NOT NULL AND
        (m2.LASTNAME IS NOT NULL OR
         m3.FIRSTNAME IS NOT NULL)

I also rewrote the query using joins instead of subselects as I think it's a bit clearer.

Note also that in the M2 and M3 joins I used LEFT OUTER with a condition of 1 = 1 rather than using CROSS JOIN , because I've noticed that CROSS JOIN acts like an INNER JOIN if the query being cross-joined returns no rows - that is, it causes the entire SELECT to return no data. dbfiddle demonstrating this situation here

I'm pretty sure you just need conditional aggregation:

SELECT d.name, d.dataid,
       MAX(CASE WHEN a1.attrid = 2 THEN a2.stringval END) as LastName,
       MAX(CASE WHEN a1.attrid = 3 THEN a2.stringval END) as FirstName
FROM directory d JOIN
     attribute2table a2
     ON a2.id = d.dataid JOIN
     attribute1table a1
     ON a1.id = d.dataid
WHERE d.dataid = 1290
GROUP BY d.name, d.dataid

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM