Home > OS >  LEFT JOIN with an AND coupled with IN operator gives errror: An expression of non-boolean type speci
LEFT JOIN with an AND coupled with IN operator gives errror: An expression of non-boolean type speci

Time:10-11

I'm trying to port a MySQL query to SQL Server. The query works fine in MySQL, but in SQL Server, it fails with the following error:

An expression of non-boolean type specified in a context where a condition is expected

I suspect it is because SQL Server doesn't like the fact that I use an AND coupled with the IN operator in the left join conditional.

QUERY

SELECT *
FROM
  (SELECT dol.Id AS 'log_id',
          c.Id AS 'computer_id',
          COALESCE(r.processor_test, 'Skipped') as 'processor_test',
  COALESCE(r.display_test, 'Skipped') as 'display_test',
  COALESCE(r.storage_test, 'Skipped') as 'storage_test',
  COALESCE(r.network_test, 'Skipped') as 'network_test',
  COALESCE(r.keyboard_test, 'Skipped') as 'keyboard_test',
  COALESCE(r.mouse_test, 'Skipped') as 'mouse_test',
          COALESCE(user_fields.customer_id, 'None') AS 'customer_id',
          COALESCE(user_fields.order_no, 'None') AS 'order_no',
          COALESCE(user_fields.technician_id, 'None') AS 'technician_id',
          CONCAT('Customer ID: ', customer_id, '<br>Order No: ', order_no, '<br>Technician ID: ', technician_id) AS 'userfields',
          hd.Id AS 'hard_disk_id',
          dol.StartTime AS 'start_time',
          hd.Serial AS 'hard_disk_serial',
          CONCAT(hd.Gigabytes, ' GB') AS 'gigabytes',
          CONCAT('<b>Vendor: </b>', hd.Vendor, '<br><br><b>Model: </b>', hd.Product, '<br><br><b>Serial: </b>', hd.Serial, '<br><br><b>Size: </b>', hd.Gigabytes, ' GB<br><br><b>Pre-wipe SMART health status: ', dol.SmartOverallPre, '<br><br><b>Post-wipe SMART health status: ', dol.SmartOverallPost) AS 'target_drive_detailed',
          CONCAT('Vendor: ', hd.Vendor, '<br><br>Product: ', hd.Product, '<br><br>Serial: ', hd.Serial, '<br><br>Drive Media Type: ', hd.DriveMediaType , '<br><br>Size: ', hd.Gigabytes, ' GB<br><br><b>Interface: ', hd.Interface) AS 'drive_detailed',
          CONCAT(hd.Serial, ' (',hd.Gigabytes, ' GB)') AS 'target_drive',
          CASE
              WHEN dol.PatternName = 'NIST 800-88r1 (recommended)' THEN 'NIST 800-88r1'
              ELSE dol.PatternName
          END AS 'pattern_name',
          CASE
              WHEN dol.Success = '1' THEN 'SUCCESS'
              WHEN dol.Success = '0' THEN 'FAILED'
          END AS 'wipe_status',
          dol.Errors AS 'errors',
          dol.DirtySectors AS 'dirty_sectors',
          dol.Tool AS 'tool',
          dol.Kernel AS 'kernel',
          dol.JobUUID AS 'job_uuid',
          dol.UUID AS 'uuid',
          CONVERT(VARCHAR(20), dol.EndTime, 120) AS 'end_time',
          substring(CONVERT(VARCHAR(20), dol.EndTime, 120), 1, 11) AS 'end_time_short',
          dol.NumPasses AS 'num_passes',
          dol.TrimPasses AS 'trim_passes',
          dol.SectorsOverwritten AS 'sectors_overwritten',
          dol.SectorsNotOverWritten AS 'sectors_not_overwritten',
          dol.SectorsVerified AS 'sectors_verified',
          dol.CustomField AS 'custom_field_legacy',
          CASE
              WHEN dol.NISTMethodTypeId = '1' THEN 'Unknown'
              WHEN dol.NISTMethodTypeId = '2' THEN 'Clear'
              WHEN dol.NISTMethodTypeId = '3' THEN 'Purge'
          END AS 'nis_method_type',
          CASE 
              WHEN dol.DCOFound = '1' AND dol.DcoRemoved = '1' THEN CONCAT('Yes /</td><td> Yes', ' ') 
              WHEN dol.DCOFound = '0' AND dol.DcoRemoved = '0' THEN CONCAT('No /</td><td> No', ' ') 
              WHEN dol.DCOFound = '1' AND dol.DcoRemoved = '0' THEN CONCAT('Yes /</td><td> No', ' ') 
              WHEN dol.DCOFound = '0' AND dol.DcoRemoved = '1' THEN CONCAT('No /</td><td> Yes', ' ') 
          END AS 'dco_foundremoved',
          CASE
              WHEN dol.DCOLocked = '1' THEN 'Yes'
              WHEN dol.DCOLocked = '0' THEN 'No'
          END AS 'dco_locked',
          CASE 
              WHEN dol.HPAFound = '1' AND dol.HPARemoved = '1' THEN CONCAT('Yes /</td><td> Yes', ' ') 
              WHEN dol.HPAFound = '0' AND dol.HPARemoved = '0' THEN CONCAT('No /</td><td> No', ' ') 
              WHEN dol.HPAFound = '1' AND dol.HPARemoved = '0' THEN CONCAT('Yes /</td><td> No', ' ') 
              WHEN dol.HPAFound = '0' AND dol.HPARemoved = '1' THEN CONCAT('No /</td><td> Yes', ' ') 
          END AS 'hpa_foundremoved',
          CASE 
              WHEN dol.AMAXFound = '1' AND dol.AMAXRemoved = '1' THEN CONCAT('Yes /</td><td> Yes', ' ') 
              WHEN dol.AMAXFound = '0' AND dol.AMAXRemoved = '0' THEN CONCAT('No /</td><td> No', ' ') 
              WHEN dol.AMAXFound = '1' AND dol.AMAXRemoved = '0' THEN CONCAT('Yes /</td><td> No', ' ') 
              WHEN dol.AMAXFound = '0' AND dol.AMAXRemoved = '1' THEN CONCAT('No /</td><td> Yes', ' ') 
          END AS 'amax_foundremoved',
          c.Vendor AS 'vendor',
          c.Model AS 'computer_model',
          c.ComputerSerial AS 'computer_serial',
          CONCAT('<b>Vendor: </b>', c.Vendor, '<br><br><b>Model: </b>', c.Model, '<br><br><b>Serial: </b>', c.ComputerSerial) as 'computer_summary',
          CONCAT('<b>Vendor: </b>', c.MotherboardVendor, '<br><br><b>Model: </b>', c.MotherboardModel) as 'motherboard_summary',
          CONCAT(first_cpu.Name, ' ', first_cpu.Speed) as 'cpu_summary',
          CONCAT(first_nic.Vendor, '<br><br>', first_nic.Product) as 'nic_summary',
          CONCAT(first_vc.Vendor, '<br><br>', first_vc.Product) as display_summary,
          CONCAT('<b>USB1 Ports: </b>', c.UsbPorts, '<br><br><b>USB2 Ports: </b>', c.Usb2Ports, '<br><br><b>USB3 Ports: </b>', c.Usb3Ports) as usb_ports,
          c.Memory AS 'computer_memory',
          hd.DriveMediaType AS 'hard_disk_drive_media_type',
          hd.Product AS 'hard_disk_product',
          hd.Vendor AS 'hard_disk_vendor'
   FROM DiskOperationLog dol
   LEFT JOIN
     (SELECT juf.JobUUID AS 'juf_job_uuid',
             COALESCE(max(CASE
                              WHEN juf.FieldName = 'Customer ID' THEN juf.FieldValue
                          END), 'None') AS customer_id,
             COALESCE(max(CASE
                              WHEN juf.FieldName = 'Order No' THEN juf.FieldValue
                          END), 'None') AS order_no,
             COALESCE(max(CASE
                              WHEN juf.FieldName = 'Technician ID' THEN juf.FieldValue
                          END), 'None') AS technician_id
      FROM DiskOperationLog dol
      INNER JOIN JobUserFields juf ON dol.JobUUID = juf.JobUUID
      GROUP BY juf.JobUUID) user_fields ON dol.JobUUID = user_fields.juf_job_uuid
   LEFT JOIN HardDisk hd ON hd.Id = dol.HardDiskId and (hd.Id, dol.EndTime) IN (select max(hd.Id) as Id, max(dol.EndTime) as EndTime from DiskOperationLog dol join HardDisk hd on hd.Id = dol.HardDiskId group by hd.Id)
   LEFT JOIN Computer c ON c.Id = hd.ComputerId
   LEFT JOIN
(select t.computer_id, 
    MAX(
        CASE 
            WHEN Type='Processor' 
            THEN Result
            ELSE NULL
        END
    ) AS 'processor_test',
    MAX(
        CASE 
            WHEN Type='Display' 
            THEN Result
            ELSE NULL
        END
    ) AS 'display_test',
    MAX(
        CASE
            WHEN Type='Network' 
            THEN Result
            ELSE NULL
        END
    ) AS 'network_test',
    MAX(
        CASE 
            WHEN Type='Keyboard'
            THEN Result
            ELSE NULL
        END
    ) AS 'keyboard_test',
    MAX(
        CASE 
            WHEN Type='Mouse'
            THEN Result
            ELSE NULL
        END
    ) AS 'mouse_test',
    MAX(
        CASE 
            WHEN Type='Storage'
            THEN Result
            ELSE NULL
        END
    ) AS 'storage_test'
  from (    
    select c.Id as computer_id,
        hst.Type, 
        case min(
            case hst.Result 
              when'Fail' then 1
              when'Skipped' then 2
              when'Pass' then 3
            end) 
          when 1 then 'Fail' 
          when 2 then 'Skipped'     
          when 3 then 'Pass'
        end Result
    from Computer c
    inner join HardwareTest ht on c.Id = ht.ComputerId
    inner join HardwareSubTest hst on ht.Id = hst.HardwareTestId
    group by c.Id, hst.Type
    ) t
 group by computer_id) r on c.Id = r.computer_id
   JOIN
     (SELECT *
      FROM Cpu cpu
      WHERE Id in
          (SELECT min(Id)
           FROM Cpu
           GROUP BY ComputerId)) AS first_cpu ON c.Id = first_cpu.ComputerId
   JOIN
     (SELECT *
      FROM Nic nic
      WHERE Id in
          (SELECT min(Id)
           FROM Nic
           GROUP BY ComputerId)) AS first_nic ON c.Id = first_nic.ComputerId
   JOIN
     (SELECT *
      FROM VideoCard vc
      WHERE Id in
          (SELECT min(Id)
           FROM VideoCard
           GROUP BY ComputerId)) AS first_vc ON c.Id = first_vc.ComputerId) AS query_result

I'm not sure why though, the use of AND in a LEFT JOIN is supported in SQL Server. What am I missing?

screenshot

CodePudding user response:

The use of AND in JOINs is supported in SQL Server, but you can not match multiple columns. SQL server permits only one column.

Try changing your join with this:

   LEFT JOIN HardDisk hd 
   ON hd.Id = dol.HardDiskId 
   and hd.Id in (select max(hd.Id) from DiskOperationLog dol join HardDisk hd on hd.Id = dol.HardDiskId group by hd.Id)
   AND dol.EndTime in (select max(dol.EndTime) from DiskOperationLog dol join HardDisk hd on hd.Id = dol.HardDiskId group by hd.Id)

CodePudding user response:

As mentioned in the other answer, SQL Server does not support row-value comparators.

But to avoid repeating code, you can use an APPLY

   OUTER APPLY (
      select
        MaxId = max(hd.Id),
        MaxEndTime = max(dol.EndTime)
      from DiskOperationLog dol2
      join HardDisk hd on hd.Id = dol2.HardDiskId
      group by hd.Id
   ) dol2
   LEFT JOIN HardDisk hd 
   ON hd.Id = dol.HardDiskId 
   and hd.Id = dol2.MaxId
   AND dol.EndTime = dol2.MaxEndTime

I must say, this whole query looks like it could do with a good dose of window functions, especially this section above.

  • Related