\n
MySQL cheat sheet
\n Time series:\n
\n - \n return column named time or time_sec (in UTC), as a unix time stamp or any sql native date data type. You can\n use the macros below.\n
\n - return column(s) with numeric datatype as values
\n
\n Optional:\n
\n - \n return column named metric to represent the series name.\n
\n - If multiple value columns are returned the metric column is used as prefix.
\n - If no column named metric is found the column name of the value column is used as series name
\n
\n
Resultsets of time series queries need to be sorted by time.
\n Table:\n
\n - return any set of columns
\n
\n Macros:\n
\n - $__time(column) -> UNIX_TIMESTAMP(column) as time_sec
\n - $__timeEpoch(column) -> UNIX_TIMESTAMP(column) as time_sec
\n - $__timeFilter(column) -> column BETWEEN FROM_UNIXTIME(1492750877) AND FROM_UNIXTIME(1492750877)
\n - $__unixEpochFilter(column) -> time_unix_epoch > 1492750877 AND time_unix_epoch < 1492750877
\n - \n $__unixEpochNanoFilter(column) -> column >= 1494410783152415214 AND column <= 1494497183142514872\n
\n - \n $__timeGroup(column,'5m'[, fillvalue]) -> cast(cast(UNIX_TIMESTAMP(column)/(300) as signed)*300\n as signed) by setting fillvalue grafana will fill in missing values according to the interval fillvalue can be\n either a literal value, NULL or previous; previous will fill in the previous seen value or NULL if none has\n been seen yet\n
\n - \n $__timeGroupAlias(column,'5m') -> cast(cast(UNIX_TIMESTAMP(column)/(300) as signed)*300 as\n signed) AS "time"\n
\n - $__unixEpochGroup(column,'5m') -> column DIV 300 * 300
\n - $__unixEpochGroupAlias(column,'5m') -> column DIV 300 * 300 AS "time"
\n
\n
Example of group by and order by with $__timeGroup:
\n
\n \n $__timeGroupAlias(timestamp_col, '1h'), sum(value_double) as value\n
\n FROM yourtable\n
\n GROUP BY 1
\n ORDER BY 1\n
\n
\n
\n Or build your own conditionals using these macros which just return the values:\n
\n - $__timeFrom() -> FROM_UNIXTIME(1492750877)
\n - $__timeTo() -> FROM_UNIXTIME(1492750877)
\n - $__unixEpochFrom() -> 1492750877
\n - $__unixEpochTo() -> 1492750877
\n - $__unixEpochNanoFrom() -> 1494410783152415214
\n - $__unixEpochNanoTo() -> 1494497183142514872
\n
\n
\n );\n}\n\nfunction getStyles(theme: GrafanaTheme2) {\n return {\n ulPadding: css({\n margin: theme.spacing(1, 0),\n paddingLeft: theme.spacing(5),\n }),\n };\n}\n","import { RAQBFieldTypes, SQLSelectableValue } from '@grafana/sql';\n\nexport function mapFieldsToTypes(columns: SQLSelectableValue[]) {\n const fields: SQLSelectableValue[] = [];\n for (const col of columns) {\n let type: RAQBFieldTypes = 'text';\n switch (col.type?.toUpperCase()) {\n case 'BOOLEAN':\n case 'BOOL': {\n type = 'boolean';\n break;\n }\n case 'BYTES':\n case 'VARCHAR': {\n type = 'text';\n break;\n }\n case 'FLOAT':\n case 'FLOAT64':\n case 'INT':\n case 'INTEGER':\n case 'INT64':\n case 'NUMERIC':\n case 'BIGNUMERIC': {\n type = 'number';\n break;\n }\n case 'DATE': {\n type = 'date';\n break;\n }\n case 'DATETIME': {\n type = 'datetime';\n break;\n }\n case 'TIME': {\n type = 'time';\n break;\n }\n case 'TIMESTAMP': {\n type = 'datetime';\n break;\n }\n case 'GEOGRAPHY': {\n type = 'text';\n break;\n }\n default:\n break;\n }\n\n fields.push({ ...col, raqbFieldType: type, icon: mapColumnTypeToIcon(col.type!.toUpperCase()) });\n }\n return fields;\n}\n\nexport function mapColumnTypeToIcon(type: string) {\n switch (type) {\n case 'TIME':\n case 'DATETIME':\n case 'TIMESTAMP':\n return 'clock-nine';\n case 'BOOLEAN':\n return 'toggle-off';\n case 'INTEGER':\n case 'FLOAT':\n case 'FLOAT64':\n case 'INT':\n case 'SMALLINT':\n case 'BIGINT':\n case 'TINYINT':\n case 'BYTEINT':\n case 'INT64':\n case 'NUMERIC':\n case 'DECIMAL':\n return 'calculator-alt';\n case 'CHAR':\n case 'VARCHAR':\n case 'STRING':\n case 'BYTES':\n case 'TEXT':\n case 'TINYTEXT':\n case 'MEDIUMTEXT':\n case 'LONGTEXT':\n return 'text';\n case 'GEOGRAPHY':\n return 'map';\n default:\n return undefined;\n }\n}\n","import { isEmpty } from 'lodash';\n\nimport { SQLQuery, createSelectClause, haveColumns } from '@grafana/sql';\n\nexport function toRawSql({ sql, dataset, table }: SQLQuery): string {\n let rawQuery = '';\n\n // Return early with empty string if there is no sql column\n if (!sql || !haveColumns(sql.columns)) {\n return rawQuery;\n }\n\n rawQuery += createSelectClause(sql.columns);\n\n if (dataset && table) {\n rawQuery += `FROM ${dataset}.${table} `;\n }\n\n if (sql.whereString) {\n rawQuery += `WHERE ${sql.whereString} `;\n }\n\n if (sql.groupBy?.[0]?.property.name) {\n const groupBy = sql.groupBy.map((g) => g.property.name).filter((g) => !isEmpty(g));\n rawQuery += `GROUP BY ${groupBy.join(', ')} `;\n }\n\n if (sql.orderBy?.property.name) {\n rawQuery += `ORDER BY ${sql.orderBy.property.name} `;\n }\n\n if (sql.orderBy?.property.name && sql.orderByDirection) {\n rawQuery += `${sql.orderByDirection} `;\n }\n\n // Altough LIMIT 0 doesn't make sense, it is still possible to have LIMIT 0\n if (sql.limit !== undefined && sql.limit >= 0) {\n rawQuery += `LIMIT ${sql.limit} `;\n }\n return rawQuery;\n}\n\n// Puts backticks (`) around the identifier if it is necessary.\nexport function quoteIdentifierIfNecessary(value: string) {\n return isValidIdentifier(value) ? value : `\\`${value}\\``;\n}\n\n/**\n * Validates the identifier from MySql and returns true if it\n * doesn't need to be escaped.\n */\nexport function isValidIdentifier(identifier: string): boolean {\n const isValidName = /^[a-zA-Z_][a-zA-Z0-9_$]*$/g.test(identifier);\n const isReservedWord = RESERVED_WORDS.includes(identifier.toUpperCase());\n return !isReservedWord && isValidName;\n}\n\n// remove identifier quoting from identifier to use in metadata queries\nexport function unquoteIdentifier(value: string) {\n if (value[0] === '\"' && value[value.length - 1] === '\"') {\n return value.substring(1, value.length - 1).replace(/\"\"/g, '\"');\n } else if (value[0] === '`' && value[value.length - 1] === '`') {\n return value.substring(1, value.length - 1);\n } else {\n return value;\n }\n}\n\nexport function quoteLiteral(value: string) {\n return \"'\" + value.replace(/'/g, \"''\") + \"'\";\n}\n\n/**\n * Copied from MySQL 8.0.31 INFORMATION_SCHEMA.KEYWORDS\n */\nconst RESERVED_WORDS = [\n 'ACCESSIBLE',\n 'ADD',\n 'ALL',\n 'ALTER',\n 'ANALYZE',\n 'AND',\n 'AS',\n 'ASC',\n 'ASENSITIVE',\n 'BEFORE',\n 'BETWEEN',\n 'BIGINT',\n 'BINARY',\n 'BLOB',\n 'BOTH',\n 'BY',\n 'CALL',\n 'CASCADE',\n 'CASE',\n 'CHANGE',\n 'CHAR',\n 'CHARACTER',\n 'CHECK',\n 'COLLATE',\n 'COLUMN',\n 'CONDITION',\n 'CONSTRAINT',\n 'CONTINUE',\n 'CONVERT',\n 'CREATE',\n 'CROSS',\n 'CUBE',\n 'CUME_DIST',\n 'CURRENT_DATE',\n 'CURRENT_TIME',\n 'CURRENT_TIMESTAMP',\n 'CURRENT_USER',\n 'CURSOR',\n 'DATABASE',\n 'DATABASES',\n 'DAY_HOUR',\n 'DAY_MICROSECOND',\n 'DAY_MINUTE',\n 'DAY_SECOND',\n 'DEC',\n 'DECIMAL',\n 'DECLARE',\n 'DEFAULT',\n 'DELAYED',\n 'DELETE',\n 'DENSE_RANK',\n 'DESC',\n 'DESCRIBE',\n 'DETERMINISTIC',\n 'DISTINCT',\n 'DISTINCTROW',\n 'DIV',\n 'DOUBLE',\n 'DROP',\n 'DUAL',\n 'EACH',\n 'ELSE',\n 'ELSEIF',\n 'EMPTY',\n 'ENCLOSED',\n 'ESCAPED',\n 'EXCEPT',\n 'EXISTS',\n 'EXIT',\n 'EXPLAIN',\n 'FALSE',\n 'FETCH',\n 'FIRST_VALUE',\n 'FLOAT',\n 'FLOAT4',\n 'FLOAT8',\n 'FOR',\n 'FORCE',\n 'FOREIGN',\n 'FROM',\n 'FULLTEXT',\n 'FUNCTION',\n 'GENERATED',\n 'GET',\n 'GRANT',\n 'GROUP',\n 'GROUPING',\n 'GROUPS',\n 'HAVING',\n 'HIGH_PRIORITY',\n 'HOUR_MICROSECOND',\n 'HOUR_MINUTE',\n 'HOUR_SECOND',\n 'IF',\n 'IGNORE',\n 'IN',\n 'INDEX',\n 'INFILE',\n 'INNER',\n 'INOUT',\n 'INSENSITIVE',\n 'INSERT',\n 'INT',\n 'INT1',\n 'INT2',\n 'INT3',\n 'INT4',\n 'INT8',\n 'INTEGER',\n 'INTERSECT',\n 'INTERVAL',\n 'INTO',\n 'IO_AFTER_GTIDS',\n 'IO_BEFORE_GTIDS',\n 'IS',\n 'ITERATE',\n 'JOIN',\n 'JSON_TABLE',\n 'KEY',\n 'KEYS',\n 'KILL',\n 'LAG',\n 'LAST_VALUE',\n 'LATERAL',\n 'LEAD',\n 'LEADING',\n 'LEAVE',\n 'LEFT',\n 'LIKE',\n 'LIMIT',\n 'LINEAR',\n 'LINES',\n 'LOAD',\n 'LOCALTIME',\n 'LOCALTIMESTAMP',\n 'LOCK',\n 'LONG',\n 'LONGBLOB',\n 'LONGTEXT',\n 'LOOP',\n 'LOW_PRIORITY',\n 'MASTER_BIND',\n 'MASTER_SSL_VERIFY_SERVER_CERT',\n 'MATCH',\n 'MAXVALUE',\n 'MEDIUMBLOB',\n 'MEDIUMINT',\n 'MEDIUMTEXT',\n 'MIDDLEINT',\n 'MINUTE_MICROSECOND',\n 'MINUTE_SECOND',\n 'MOD',\n 'MODIFIES',\n 'NATURAL',\n 'NOT',\n 'NO_WRITE_TO_BINLOG',\n 'NTH_VALUE',\n 'NTILE',\n 'NULL',\n 'NUMERIC',\n 'OF',\n 'ON',\n 'OPTIMIZE',\n 'OPTIMIZER_COSTS',\n 'OPTION',\n 'OPTIONALLY',\n 'OR',\n 'ORDER',\n 'OUT',\n 'OUTER',\n 'OUTFILE',\n 'OVER',\n 'PARTITION',\n 'PERCENT_RANK',\n 'PRECISION',\n 'PRIMARY',\n 'PROCEDURE',\n 'PURGE',\n 'RANGE',\n 'RANK',\n 'READ',\n 'READS',\n 'READ_WRITE',\n 'REAL',\n 'RECURSIVE',\n 'REFERENCES',\n 'REGEXP',\n 'RELEASE',\n 'RENAME',\n 'REPEAT',\n 'REPLACE',\n 'REQUIRE',\n 'RESIGNAL',\n 'RESTRICT',\n 'RETURN',\n 'REVOKE',\n 'RIGHT',\n 'RLIKE',\n 'ROW',\n 'ROWS',\n 'ROW_NUMBER',\n 'SCHEMA',\n 'SCHEMAS',\n 'SECOND_MICROSECOND',\n 'SELECT',\n 'SENSITIVE',\n 'SEPARATOR',\n 'SET',\n 'SHOW',\n 'SIGNAL',\n 'SMALLINT',\n 'SPATIAL',\n 'SPECIFIC',\n 'SQL',\n 'SQLEXCEPTION',\n 'SQLSTATE',\n 'SQLWARNING',\n 'SQL_BIG_RESULT',\n 'SQL_CALC_FOUND_ROWS',\n 'SQL_SMALL_RESULT',\n 'SSL',\n 'STARTING',\n 'STORED',\n 'STRAIGHT_JOIN',\n 'SYSTEM',\n 'TABLE',\n 'TERMINATED',\n 'THEN',\n 'TINYBLOB',\n 'TINYINT',\n 'TINYTEXT',\n 'TO',\n 'TRAILING',\n 'TRIGGER',\n 'TRUE',\n 'UNDO',\n 'UNION',\n 'UNIQUE',\n 'UNLOCK',\n 'UNSIGNED',\n 'UPDATE',\n 'USAGE',\n 'USE',\n 'USING',\n 'UTC_DATE',\n 'UTC_TIME',\n 'UTC_TIMESTAMP',\n 'VALUES',\n 'VARBINARY',\n 'VARCHAR',\n 'VARCHARACTER',\n 'VARYING',\n 'VIRTUAL',\n 'WHEN',\n 'WHERE',\n 'WHILE',\n 'WINDOW',\n 'WITH',\n 'WRITE',\n 'XOR',\n 'YEAR_MONTH',\n 'ZEROFILL',\n];\n","import { quoteLiteral, unquoteIdentifier } from './sqlUtil';\n\nexport function buildTableQuery(dataset?: string) {\n const database = dataset !== undefined ? quoteIdentAsLiteral(dataset) : 'database()';\n return `SELECT table_name FROM information_schema.tables WHERE table_schema = ${database} ORDER BY table_name`;\n}\n\nexport function showDatabases() {\n return `SELECT DISTINCT TABLE_SCHEMA from information_schema.TABLES where TABLE_TYPE != 'SYSTEM VIEW' ORDER BY TABLE_SCHEMA`;\n}\n\nexport function buildColumnQuery(table: string, dbName?: string) {\n let query = 'SELECT column_name, data_type FROM information_schema.columns WHERE ';\n query += buildTableConstraint(table, dbName);\n\n query += ' ORDER BY column_name';\n\n return query;\n}\n\nexport function buildTableConstraint(table: string, dbName?: string) {\n let query = '';\n\n // check for schema qualified table\n if (table.includes('.')) {\n const parts = table.split('.');\n query = 'table_schema = ' + quoteIdentAsLiteral(parts[0]);\n query += ' AND table_name = ' + quoteIdentAsLiteral(parts[1]);\n return query;\n } else {\n const database = dbName !== undefined ? quoteIdentAsLiteral(dbName) : 'database()';\n query = `table_schema = ${database} AND table_name = ` + quoteIdentAsLiteral(table);\n\n return query;\n }\n}\n\nexport function quoteIdentAsLiteral(value: string) {\n return quoteLiteral(unquoteIdentifier(value));\n}\n","import {\n CompletionItemKind,\n CompletionItemPriority,\n getStandardSQLCompletionProvider,\n LanguageCompletionProvider,\n LinkedToken,\n PositionContext,\n StatementPlacementProvider,\n SuggestionKind,\n SuggestionKindProvider,\n TableDefinition,\n TableIdentifier,\n TokenType,\n} from '@grafana/experimental';\n\ninterface CompletionProviderGetterArgs {\n getMeta: (t?: TableIdentifier) => Promise