Примеры запросов

Данная статья доступно объясняет некоторые реальные примеры запросов.

Пример 1: Просмотр/редактирование учетных записей пользователей

Просмотр или изменение различных настроек учетных записей является общей административной задачей. Язык запроса может помочь администраторам SberMobile Server выполнить массовые изменения нескольких учетных записей пользователей или посмотреть определенные настройки множества учетных записей в одной упорядоченной таблице.

Выбор информации одного пользователя

Для доступа к основным настройкам учетной записи пользователя мы используем переменную "userInfo" ("Информация о пользователе"), заданную в контексте Пользователь. Значение данной переменной имеет одну запись с различными полями, в которых записаны имя/фамилия пользователя, страна и т.д.

Ниже представлен типичный вид переменной информации о пользователе:

Теперь мы используем один из самых простых возможных запросов, чтобы получить значение данной переменной только из одного контекста.

Текст запроса:

SELECT * FROM users.admin:childInfo

Результатом данного запроса будет являться таблица, отображающая значение переменной childInfo, заданной в контексте users.admin.

При просмотре или изменении свойств некого системного объекта или устройства его имя контекста обычно показывается в заголовке окна:

Данный запрос состоит из двух разделов: ВЫБРАТЬ и ОТ. Раздел ВЫБРАТЬ предлагает нам выбрать все поля ("*"). Раздел ОТ содержит одну контекстную ссылку ("users.admin:childInfo"), которая используется для построения таблицы, в которой будет выполняться запрос. Содержание и формат данной таблицы в точности совпадут с переменной childInfo.

Все поля в результате запроса будут доступны для редактирования, кроме тех полей, которые определены как доступные только для чтения в формате переменной childInfo.

При просмотре или изменении свойств какого-либо контекста (такого как контекст "Пользователь") вы увидите описания переменных, а не их имена. Однако в тесте запроса нам нужно использовать имена переменных: они обычно показываются во всплывающих окнах при наведении мыши на описание переменных:

   

Результат запроса:

Выбор информации всех пользователей

Теперь мы будем выбирать свойства всех пользователей в системе:

Текст запроса:

SELECT

 *

FROM

 users.*:childInfo

Контекстная ссылка (users.*:childInfo) в тексте данного запроса по сути является маской контекстов. Во время выполнения запроса данная маска преобразуется в список всех контекстов пользователей, доступных пользователю, выполняющему запрос. Для получения более подробной информации обратитесь к главе Контекстные ссылки.

Результатом данного запроса станет таблица со значениями переменной childInfo каждой учетной записи, доступной пользователю, выполняющему запрос. Возможно, она будет содержать множество записей, по одной на каждую учетную запись. Результат запроса также доступен для редактирования.

Данный запрос встроен в дистрибутив SberMobile Server. Он называется Все пользователи.

Результат запроса:

Например, вы изменяете имя и фамилию некого пользователя и сохраняете изменения:

Изменения сразу же отображаются во всей системе:

Сортировка  списка пользователей

Теперь мы произведем сортировку таблицы.

Текст запроса:

SELECT

 *

FROM

 users.*:childInfo order by childInfo$name desc

Данный запрос выдает таблицу, схожую с указанной выше, но строки в данной таблице упорядочиваются по значению поля name в формате переменной childInfo в нисходящем порядке. Запрос содержит состоящую из двух частей ссылку на поле (childInfo$name), используемую для ссылки на поле таблицы, построенной при разрешении контекстной ссылки users.*:childInfo.

При изучении значения переменной "childInfo"  и других переменных SberMobile IIoT Platform Client в пользовательском интерфейсе SberMobile Server описания полей отображаются в заголовке таблицы, а не в именах полей. Однако мы должны использовать имя поля, чтобы ссылаться на него в тексте запроса. Имена полей обычно отображаются во всплывающих окнах, которые появляются при наведении мыши на заголовок поля:

   

Результат запроса:

Использование альтернативных имен таблиц

Мы можем редактировать запрос и задать альтернативное имя info для нашей контекстной ссылки, а затем использовать трехкомпонентную контекстную ссылку, которая будет включать данное альтернативное имя:

SELECT

 *

FROM

 users.*:childInfo as info

ORDER BY

 info.childInfo$name desc

Результат запроса будет такой же, как и предыдущий.

Ограничение выборки полей

Теперь выберем ограниченное количество полей при помощи последующего изменения того же запроса.

Текст запроса:

SELECT

 childInfo$name, childInfo$firstname, childInfo$lastname

FROM

 users.*:childInfo

ORDER BY

 childInfo$name desc

Данный запрос содержит несколько ссылок на поля в разделе ВЫБРАТЬ. Так как поля задаются в явной форме, результат запроса будет нередактируемым, если мы не добавим поля обратной записи. Добавлять их мы будем в следующих примерах.

Результат данного запроса будет содержать только три столбца.

Результат запроса:

Добавление выражений

В данном случае мы будем использовать выражение языка запроса для отображения имен и фамилий пользователей в одном столбце, чтобы упростить процесс обработки данных. Мы также добавим новый столбец в запрос - Country (страна пользователя).

Текст запроса:

SELECT

 childInfo$name,

 CASEWHEN((childInfo$firstname IS NULL), '', childInfo$firstname)  || ' ' || CASEWHEN((childInfo$lastname IS NULL), '', childInfo$lastname),

 childInfo$country

FROM

 users.*:childInfo

ORDER BY

 childInfo$name desc

Данный запрос выбирает три поля в исходной таблице. Первое и третье содержат имя пользователя и страну соответственно. Значение второго поля рассчитывается при помощи выражения. Данное выражение получает имя пользователя, добавляет в конце место и заполняет его фамилией пользователя. Двойные вертикальные черты (||) являются стандартным оператором SQL, используемым для соединения строк. Имя и фамилия изменяются при помощи встроенной функции CASEWHEN, чтобы отображалась пустая строка в том случае, если значение имени или фамилии является NULL ("<Не установлено>"). Имейте в виду, что второй столбец формируется автоматически.

Результат запроса:

Использование альтернативных имен полей

Теперь мы зададим название для второго столбца, чтобы сделать результат более удобным для чтения.

Текст запроса:

SELECT

childInfo$name,

 CASEWHEN((childInfo$firstname IS NULL), '', childInfo$firstname)  || ' ' || CASEWHEN((childInfo$lastname IS NULL), '', childInfo$lastname) as name,

childInfo$country

FROM

 users.*:childInfo

ORDER BY

childInfo$name desc

Второй столбец в результате запроса отныне называется "name" (имя).

Результат запроса:

Возможность редактирования результата

Чтобы было возможно изменить страну пользователя, добавьте поле обратной записи, таким образом делая отчет редактируемым. Для этого нам нужно назначить альтернативное имя для контекстной ссылки ("table alias"),  потому как поля обратной записи (CONTEXT_ID, PARENT_ID и RECORD_INDEX) должны быть заданы для определенной контекстной ссылки. Чтобы определить, какая запись должна быть записана обратно, необходимо использовать альтернативное имя. Внимательно прочтите приведенный ниже пример, чтобы полностью в этом разобраться.

Текст запроса:

SELECT

 info.childInfo$name,

 CASEWHEN((info.childInfo$firstname IS NULL), '', info.childInfo$firstname)  || ' ' || CASEWHEN((info.childInfo$lastname IS NULL), '',        info.childInfo$lastname) as name,

 info.childInfo$country,

 info.CONTEXT_ID,

 info.PARENT_ID,

 info.RECORD_INDEX

FROM

 users.*:childInfo as info

ORDER BY

 info.childInfo$name desc

В результате данного запроса столбец "country" будет редактируемым. Столбец "username" останется доступным для чтения, потому что он так определен в исходной переменной ("userInfo"). Столбец "name" доступен только для чтения, т.к. он рассчитывается при помощи выражения.

Результат запроса:

Фильтрация списка пользователей

Теперь добавим к запросу несколько правил фильтра. Для примера выберем только тех пользователей, чьи имена пользователей (usernames) не содержат слово "test".

Текст запроса:

SELECT

 info.childInfo$name,

 CASEWHEN((info.childInfo$firstname IS NULL), '', info.childInfo$firstname)  || ' ' || CASEWHEN((info.childInfo$lastname IS NULL), '',        info.childInfo$lastname) as name,

 info.childInfo$country,

 info.CONTEXT_ID,

 info.PARENT_ID,

 info.RECORD_INDEX

FROM

 users.*:childInfo as info

WHERE

 info.childInfo$name NOT LIKE '%test%'

ORDER BY

 info.childInfo$name desc

Данный запрос содержит дополнительный раздел ГДЕ, определяющий, какие записи должны попадать в результат.

Результат запроса:

Ограничение количества строк в результате запроса

Последняя строка следующего примера включает раздел ОГРАНИЧИТЬ, используемый для ограничения количества строк в результате запроса.

Текст запроса:

SELECT

 info.childInfo$name,

 CASEWHEN((info.childInfo$firstname IS NULL), '', info.childInfo$firstname)  || ' ' || CASEWHEN((info.childInfo$lastname IS NULL), '',        info.childInfo$lastname) as name,

 info.childInfo$country,

 info.CONTEXT_ID,

 info.PARENT_ID,

 info.RECORD_INDEX

FROM

 users.*:childInfo as info

WHERE

 info.childInfo$name NOT LIKE '%test%'

ORDER BY

 info.childInfo$name desc

LIMIT 2 OFFSET 1

Результат данного запроса содержит только две (LIMIT 2) записи (2-ую и 3-ю) из результата предыдущего запроса. Здесь мы используем OFFSET 1. Это означает, что мы получим 2 записи (LIMIT 2), начиная со второй записи (OFFSET 1). Оператор OFFSET дает команду SberMobile брать записи, начиная со второй (номер первой записи - 0).

Результат запроса:

Пример 2:  просмотр/изменение учетных записей device server

Данный пример похож на выборку основных свойств всех пользователей, описанную в предыдущем примере, однако, здесь мы используем переменную deviceServerInfo (Информация устройства), заданную в контексте"deviceServer".

Текст запроса:

SELECT

 *

FROM

 users.*.deviceservers.*:deviceServerInfo

Текст данного запроса включает одну контекстную ссылку (users.*.deviceservers.*:deviceServerInfo) с маской контекста, которая распространяется на все контексты deviceServer, доступные при наличии прав доступа у пользователя, выполняющего запрос. Результаты данного запроса редактируемы, за исключением полей, которые определены как доступные только для чтения в переменной deviceServerInfo.

Данный запрос встроен в дистрибутив SberMobile Server. Он называется Все Device Servers.

Результат запроса:

Пример 3:  просмотр статистики трафика device server

Данный пример показывает применение контекстных ссылок, включающих в себя множество переменных/полей.

Текст запроса:

SELECT

info.deviceServerInfo$owner,

info.deviceServerInfo$name,

info.status$servertods,

info.status$dstoserver

FROM

users.*.deviceservers.*:status:deviceServerInfo as info

ORDER BY

info.deviceServerInfo$owner,

info.deviceServerInfo$name

Контекстная ссылка в данном запросе ("users.*.deviceservers.*:status:deviceServerInfo") ссылается на две переменные, определенные в контексте "deviceServer": на указанную выше "deviceServerInfo" и "status" ("Статус устройства"), которая содержит реальные значения относительно работы Device Server. Значения обеих переменных включают только одну запись, поэтому итоговая таблица, которая сформируется после преобразования этой  контекстной ссылки, будет содержать все поля, появляющиеся в в значениях обеих переменных, и одну запись на каждое Device Server доступное пользователю, выполняющему запрос.

Из этой таблицы мы выбираем четыре столбца: два, которые появляются в значении deviceServerInfo (Владелец и имя Device Server) и два из status (Входящий и исходящий трафик). Таблица упорядочивается по двум полям: сначала по владельцу Device Server, затем по имени Device Server (потому что некоторые Device Server могут принадлежать одному пользователю).

Данный запрос встроен в дистрибутив SberMobile Server. Он называется Статистика трафика Device Server.

Результат запроса:

Пример 4:  вызов серверов устройств

Данный пример показывает, как функции контекста могут быть использованы в данном запросе.

Текст запроса:

SELECT

 *

FROM

 external_device_servers.*:buzz()

Данный запрос очень интересен, потому что у него нет выхода, однако, он дает побочный эффект на сервере. Он  содержит одну контекстную переменную ("external_device_servers.*:buzz()"), которая включает в себя функцию buzz() ("Вызвать Device Server"), заданную в контексте "deviceServer". Данная функция вызывается без параметров, что обозначено пустыми скобками. Функция "Вызвать устройство" заставляет Device Server мерцать диодами для его физической идентификации. Таким образом, данный запрос помогает определить местонахождение всех устройств в сегменте локальной сети. Важно запустить действие Обнаружить <Device Server до выполнения запроса. Данное действие позволяет SberMobile Server найти все локальные Device Server, отправляя широковещательные сетевые запросы. Для получения более подробной информации обратитесь к разделу Внешние серверы устройств.

Если обнаружение не было выполнено, у контекста Внешние серверы устройств не будет дочерних, маска контекста external_device_servers.* не преобразуется ни в какой контекст, и при выполнении запроса не будут совершаться действия.

Выход функции buzz() не содержит полей, поэтому данный запрос не возвращает никаких данных. Но его выполнение приводит к тому, что все внешние Device Server начинают "мигать", таким образом становится проще их обнаружить.

Данный запрос встроен в дистрибутив SberMobile Server. Он называется "Вызвать все внешние Device Servers".

Пример 5:  расчет общего трафика всех серверов устройств

Данный пример показывает, как можно использовать функцию агрегации.

Текст запроса:

SELECT

 SUM(status$servertods) as server_to_ds,

 SUM(status$dstoserver) as ds_to_server

FROM

 users.*.deviceservers.*:status

В одном из предыдущих примеров мы упоминали переменную status ("Статус Device Server"), заданную в контексте "deviceServer", которая содержит статистику трафика между SberMobile Server и Device Server. Данный запрос раcсчитывает, сколько байт было отправлено на видимые в данный момент Device Server и сколько было принято от них. Результат запроса содержит одну запись, потому что используется функция агрегации SUM.

Результат запроса:

Поскольку результат запроса содержит только одну строку, он отображается в виде "вертикального" шаблона из двух столбцов, где имена полей записаны в первом столбце, а значения полей -- во втором.

Данный пример можно изменить для использования других функций агрегации:

  • AVG поможет рассчитать средний трафик Device Server
  • MIN и MAX могут применяться для расчета минимального и максимального трафика соответственно
  • COUNT может использоваться для обнаружения нескольких Device Server (хотя это не самый лучший  способ)

Пример 6:

Выполнение запроса по нескольким таблицам

Данный пример иллюстрирует выполнение запросов по нескольким таблицам (построенным из нескольких контекстных ссылок).

Текст запроса:

SELECT

 d.deviceServerInfo$owner || '.' || d.deviceServerInfo$name as device_server,

 d.deviceServerInfo$blocked,

 u.userInfo$city,

 u.userInfo$country

FROM

 users.*:childInfo as u, users.*.deviceservers.*:deviceServerInfo as d

WHERE

 u.childInfo$name = d.deviceServerInfo$owner

Данный запрос имеет две контекстные ссылки в разделе ОТ. Первая используется для построения таблицы, содержащей все базовые настройки всех пользователей, вторая - для формирования таблицы базовых настроек всех Device Server. Эти таблицы затем объединяются, основываясь на формуле в разделе ГДЕ ("u.childInfo$name = d.deviceServerInfo$owner"). Результат запроса имеет четыре поля: первое содержит полное имя устройства в виде "Имя владельца"."Имя Device Server". Второе отображает статус Device Server "Блокировано". Два остальных столбца показывают город и страну пользователя, к которому относятся Device Server (которые, вероятно, могут оказаться городом и страной, где расположено Device Server).

Результат запроса:

Пример 7: Использование объединить

Данный пример показывает, как использовать ОБЪЕДИНИТЬ SQL и скрытые поля для сочетания данных из двух таблиц, образованных из двух разных контекстных ссылок.

Когда SberMobile  используется для сетевого управления, SberMobile Server работает с устройствами по протоколу SNMP. Каждое устройство SNMP обладает так называемой таблицей интерфейса (переменная ifTable контекста устройства), в которой содержится статистика сетевых интерфейсов устройства. Приведенный ниже запрос находит все сетевые интерфейсы всех устройств SNMP, чей статус равен "down" (т.е. поле ifOperStatus равно 2).

Запрос добавляет описание контекста устройства (т.е. имя устройства) к описанию сетевого интерфейса, чтобы в дальнейшем отображать их в одной таблице.

SELECT

 info.info$description, ift.ifTable$ifDescr, ift.ifTable$ifOperStatus

FROM

 users.*.devices.*:ifTable as ift LEFT OUTER JOIN users.*.devices.*:info as info ON ift$CONTEXT_ID = info$CONTEXT_ID

WHERE

 ift.ifTable$ifOperStatus = 2

Результат запроса:

Дополнительные примеры

Получение события входа пользователя в систему

Данный запрос вызывает функцию get() и фильтрует полученную таблицу по имени пользователя (username).

SELECT

*

FROM

events:get("users", "login") as logins

WHERE

logins.get$username = 'operator'

Имейте в виду, что те же результаты можно получить, добавив выражение фильтра в вызов функции get():

SELECT

*

FROM

events:get("users", "login", "{username} == 'operator'") as logins

Обнаружение сетевых устройств

С минимальным временем отклика

Данный запрос обнаруживает все сетевые устройства, время отклика которых превышает 500 мсек и отображает их имена вместе с временем отклика.

SELECT

 info.info$description AS device,

 ping.ping$averageTime AS average_round_trip_time

FROM

 users.*.devices.*:info AS info

RIGHT OUTER JOIN  

 users.*.devices.*:ping AS ping

ON

 ping$CONTEXT_ID = info$CONTEXT_ID

WHERE

 ping.ping$averageTime > 500

ORDER BY

 ping.ping$averageTime DESC

Обнаружение устройств высокой загрузки ЦП

Данный запрос обнаруживает все сетевые устройства SNMP, у которых средняя загрузка всех процессоров превышает 90%. Он превосходно работает с мультипроцессорными устройствами.

SELECT

 info.info$description AS device,

 avg(processors.hrProcessorTable$hrProcessorLoad) AS processor_utilization_percentage

FROM

 users.*.devices.*:hrProcessorTable AS processors

LEFT OUTER JOIN

 users.*.devices.*:info as info

ON

 processors$CONTEXT_ID = info$CONTEXT_ID

GROUP BY

 device

HAVING

 avg(processors.hrProcessorTable$hrProcessorLoad) > 90

ORDER BY

 processor_utilization_percentage DESC

Группирование устройств SNMP по типу

Данный запрос рассчитывает количество устройств SNMP каждого типа (тип определяется переменной sysObjectID,  предоставляемой самим устройством) и выводит результат в таблицу. Имейте в виду, что описания каждого типа устройства берутся из общей таблицы, которая называется deviceTypes.

SELECT

 coalesce(types.value$description, snmp.sysObjectID$sysObjectID) AS device_type,

 COUNT(*) AS device_count

FROM

 users.*.devices.*:status:sysObjectID AS snmp

LEFT JOIN

 common.deviceTypes:value AS types

ON

 snmp.sysObjectID$sysObjectID = types.value$type

WHERE

 snmp.status$driver = 'com.tibbo.linkserver.plugin.device.snmp'

GROUP BY

 device_type

ORDER BY

 device_count DESC

Получение статистики настроек устройства

Данный запрос использует функцию статистика, заданную в контексте Утилиты для извлечения последних значений канала статистики. Канал настроен для подсчета ошибок интерфейса сетевых устройств, которые возникают каждый час/день/месяц.

Запрос группирует таблицы интерфейсов всех устройств в одну и использует ее как основу (FROM users.*.devices.*:ifTable AS interfaces). Затем он слева присоединяяет данные последнего часа из двух каналов статистики -- "ifInOctets" и "ifOutOctets" (LEFT OUTER JOIN utilities:statistics("users.*.devices.*", "ifInErrors", null, "hour") AS in_errors). И, наконец, слева таблицы присоединяется информация об устройстве. Запрос также осуществляет фильтрацию, сортировку и ограничение количества рядов.

SELECT

info.info$description AS device,

interfaces.ifTable$ifDescr AS interface,

in_errors.statistics$average * 3600 AS incoming_errors,

out_errors.statistics$average * 3600 AS outgoing_errors

FROM

users.*.devices.*:ifTable AS interfaces

LEFT OUTER JOIN

utilities:statistics("users.*.devices.*", "ifInErrors", null, "hour") AS in_errors

ON

interfaces.ifTable$ifIndex = in_errors.statistics$key

AND

interfaces$CONTEXT_ID = in_errors.statistics$context

LEFT OUTER JOIN

utilities:statistics("users.*.devices.*", "ifOutErrors", null, "hour") AS out_errors

ON

interfaces.ifTable$ifIndex = out_errors.statistics$key

AND

interfaces$CONTEXT_ID = out_errors.statistics$context

LEFT OUTER JOIN

users.*.devices.*:info AS info

ON

info$CONTEXT_ID = interfaces$CONTEXT_ID

WHERE

 length(interfaces.ifTable$ifDescr) > 1

ORDER BY

 incoming_errors + outgoing_errors DESC

LIMIT

 10

Составление списка сотрудников по отделам

В SberMobile Time and Attendance система обрабатывает данные посещения для держателей карт, образуя сложную иерархию, которая включает организации, отделы и, возможно, подразделения. Поскольку путь контекста каждого сотрудника начинается с пути контекста подразделения, к которому он относится, мы можем создать запрос, который создал бы список сотрудников по подразделениям:

SELECT

divisions.childInfo$name,

cardholders.childInfo$name

FROM

organizations.Organization1.divisions.*.cardholders.*:childInfo as cardholders,

organizations.Organization1.divisions.*:childInfo as divisions

WHERE

substring(cardholders.CONTEXT_ID, 1, length(divisions.CONTEXT_ID)) = divisions.CONTEXT_ID

Получение тревог, активных для множества устройств

В приведенном ниже примере каждое устройство имеет табличное пользовательское свойство custom_childContext,  которое приводит список всех устройств, зависимых от него. Это свойство имеет поле contextPath, которое содержит пути зависимых устройств.

Запрос проверяет триггеры, представленные в таблицах activeInstances всех тревог. Выбираются только триггеры, чье поле источник равно контекстному пути выбранного устройства (i.CONTEXT_ID) или представлено в таблице custom_childContext выбранного устройства.

Таким образом, запрос возвращает триггеры тревог, активные как для данного устройства (dev1), так и для его зависимых устройств.

SELECT

*

FROM

users.*.alerts.*:activeInstances AS at

WHERE

at.activeInstances$source IN

(

SELECT

 i.CONTEXT_ID

FROM users.admin.devices.dev1:info AS i

UNION SELECT

 c.custom_childContexts$contextPath

FROM users.admin.devices.dev1:custom_childContexts AS c

)

Объединение исторических значений множества переменных

Функция variableHistory может загружать исторические значения любой переменной контекста. Это подходит для отображения этих значений в отчете, на панели инструментов и т.д. Но что если вы хотите показать множество переменных в одной таблице? Например, вы измеряете температуру и историю и хотите, чтобы измерения были представлены в виде единой таблицы. Вот решение.

Приведенный ниже запрос загружает десятидневную историю двух отдельных переменных в двух виртуальных таблицах и объединяет эти таблицы, соединяя вместе значения с одинаковыми временными метками с точностью до одной секунды.

SELECT

  sineTimeString, sineTime,  sineValue, triangleTime, triangleValue

FROM

  (

  SELECT

    TO_CHAR(sine.variableHistory$vUpdateTime, 'DD.MM.YYYY H:MI:SS') as sineTimeString, sine.variableHistory$vUpdateTime as sineTime, sine.variableHistory$value as sineValue

  FROM

    utilities:variableHistory("users.admin.devices.demoVirtualDevice", "sine", 'dateAdd(now(), -10, "m")') as sine

  )

JOIN

  (

  SELECT

    TO_CHAR(triangle.variableHistory$vUpdateTime, 'DD.MM.YYYY H:MI:SS') as triangleTimeString, triangle.variableHistory$vUpdateTime as triangleTime, triangle.variableHistory$value as triangleValue

  FROM

    utilities:variableHistory("users.admin.devices.demoVirtualDevice", "triangle", 'dateAdd(now(), -10, "m")') as triangle

  )

ON

sineTimeString = triangleTimeString

Объединение результатов нескольких подзапросов

Приведенный ниже запрос ссылается на три других запроса, представляя список их переменных data в разделе ОТ основных и вложенных утверждений ВЫБРАТЬ. Результаты трех запросов соединяются вместе, используя операторы ОБЪЕДИНИТЬ.

SELECT

 hpux.data$icon AS icon,

 hpux.data$device AS device,

 hpux.data$context AS context,

 hpux.data$cpu AS cpu,

 hpux.data$max_threshold as max_threshold,

 hpux.data$min_threshold as min_threshold,

 hpux.data$max_threshold - hpux.data$cpu as margin,

 CASEWHEN(hpux.data$max_threshold - hpux.data$cpu < 0,

   2,

   CASEWHEN(hpux.data$max_threshold - hpux.data$cpu < 10, 1, 0) ) as condition

FROM

 users.admin.queries.cpu_HPUX:data as hpux

UNION ALL

(SELECT

 standard.data$icon AS icon,

 standard.data$device AS device,

 standard.data$context AS context,

 standard.data$cpu AS cpu,

 standard.data$max_threshold as max_threshold,

 standard.data$min_threshold as min_threshold,

 standard.data$max_threshold - standard.data$cpu as margin,

 CASEWHEN(standard.data$max_threshold - standard.data$cpu < 0,

   2,

   CASEWHEN(standard.data$max_threshold - standard.data$cpu < 10, 1, 0) ) as condition

FROM

 users.admin.queries.cpu_standard:data as standard

UNION ALL

(SELECT

 sun.data$icon AS icon,

 sun.data$device AS device,

 sun.data$context AS context,

 sun.data$cpu AS cpu,

 sun.data$max_threshold as max_threshold,

 sun.data$min_threshold as min_threshold,

 sun.data$max_threshold - sun.data$cpu as margin,

 CASEWHEN(sun.data$max_threshold - sun.data$cpu < 0,

   2,

   CASEWHEN(sun.data$max_threshold - sun.data$cpu < 10, 1, 0) ) as condition

FROM

 users.admin.queries.cpu_Sun:data as sun))

ORDER BY

 margin