Home Pattern

Tabular: SQL query

Load tabular datasets into Query Tabular for SQL joins, window calculations, and queries that combine several tabular operations.

Revised
2026-10-01
Rev
3

Pattern health

ok
  • IWC exemplar anchors

    4 abstract workflow anchors declared.

  • Foundry verification fixture

    1 verification path declared.

  • Pattern map coverage

    1 pattern map link here.

  • Metadata contract

    Pattern frontmatter matches the site contract.

Tabular: SQL query

query_tabular loads one or more tabular datasets into SQLite, runs a SELECT query, and writes tabular results. Choose it when the result needs SQL operations such as a window calculation, a join with additional predicates, or a query that combines filtering, grouping, and projection. For a single row predicate, cut, or computed column, the corresponding filter, cut, or compute pattern is usually easier to inspect. tabular-join-on-key covers joins that do not need a SQL query.

The example workflow uses toolshed.g2.bx.psu.edu/repos/iuc/query_tabular/query_tabular/3.3.2 and pins its Tool Shed changeset. Keep the version and changeset together when adapting the example.

Load tables, then query them

Each tables entry connects a tabular dataset. The first unnamed table becomes t1, the second t2, and so on. Set tbl_opts.table_name when names make a multi-table query easier to read. Columns default to c1, c2, and so on. tbl_opts.col_names assigns names by position. For example, sample,amount gives those names to the first two columns. A blank position retains its cN name. With load_named_columns: false, all columns load under those names. Set it to true only when the query should load the columns explicitly named in col_names.

Input headers and output headers are independent:

SettingEffect
tables[].input_opts.linefilters with skipRemoves leading input lines before loading. Use skip_lines: "1" for a conventional header that should not become a data row.
tables[].tbl_opts.column_names_from_first_lineTakes column names from the input’s first line. Use this instead of skipping that line when its names are suitable for SQLite.
tables[].tbl_opts.col_namesSupplies column names by position, whether or not the input has a header. It does not remove the input header row.
query_result.header"yes" writes a header for the main result from selected column names or aliases. "no" omits it. header_prefix, when set, prefixes that output header with the selected character.

The header select values are strings. Quote "yes" and "no" in YAML so they do not become booleans. Set ORDER BY when output order matters. An unordered SQL result has no promised row order, even if the input files are ordered.

Example: join and calculate within groups

The complete workflow under verification/workflows/tabular-sql-query/ accepts a counts table (sample, amount) and a cohorts table (sample, cohort). It skips both input header rows, names the loaded tables and columns, and joins by sample. The SUM(...) OVER (PARTITION BY ...) denominator is computed per cohort, so samples A and B share a denominator while C gets its own. The 100.0 keeps the division fractional.

SELECT counts.sample, cohorts.cohort, counts.amount,
       ROUND(100.0 * counts.amount /
             SUM(counts.amount) OVER (PARTITION BY cohorts.cohort), 1) AS percent
FROM counts JOIN cohorts ON counts.sample = cohorts.sample
ORDER BY counts.sample

With amounts A=2, B=3, C=5 and cohorts A=x, B=x, C=y, the output is:

sample  cohort  amount  percent
A       x       2       40.0
B       x       3       60.0
C       y       5       100.0

The Planemo test in verification_paths checks this output byte for byte, including its header and order. Its README gives the command used for the local run. A failed comparison can reveal an imported header row, the wrong join multiplicity, an incorrect window partition, or an unexpected output header.

Input filters and additional results

Line filters run in the listed order before SQLite receives rows. A comment filter with comment_char: "35" excludes lines beginning with #. prepend_dataset_name and prepend_line_num add columns, so later cN positions shift. normalize expands a delimited list into rows, which can also change join multiplicity. Check the post-filter table shape before writing the query. The MAPseq workflow filters comment lines and prepends the dataset name before its relative-abundance window query. The clinical discovery workflow skips a header, prepends line numbers, normalizes protein lists, and uses indexes for its exclusion query.

sqlquery produces the main output. Up to three addqueries.queries can produce output1, output2, and output3, each with its own query_result header setting. save_db can also expose the SQLite database as sqlitedb. Check all declared workflow outputs before treating a step as a single-result query. The MGnify rRNA workflow demonstrates additional queries.

Check the result

A successful tool job does not establish that a join or window calculation is correct. In a small fixture, assert the header, selected columns, row count, representative values, and duplicate-key behavior. If a query divides by an aggregate, include a group with a different denominator, as the fixture above does. A NULL denominator or a missing join key needs an explicit policy in the SQL and expected output.

The Query Tabular wrapper defines the inputs and output names. Its macros define line filters and header settings. See iwc-tabular-operations-survey for the pinned corpus inventory and tabular-join-on-key for a comparison with dedicated join tools.

IWC exemplars 4 anchors

IWC Exemplars

amplicon/amplicon-mgnify/mapseq-to-ampvis2/mapseq-to-ampvis2 high

Uses a single-table SUM window function for relative abundance after input line filtering.

amplicon/amplicon-mgnify/mgnify-amplicon-pipeline-v5-rrna-prediction/mgnify-amplicon-pipeline-v5-rrna-prediction high

Shows one input with a main query and additional query outputs.

proteomics/clinicalmp/clinicalmp-verification/clinicalmp-verification high

Joins two named input tables and selects columns from each.

proteomics/clinicalmp/clinicalmp-discovery/iwc-clinicalmp-discovery-workflow high

Excludes rows using a three-table query after skipping headers, numbering lines, and normalizing a list column.

Incoming References (9)

  • Galaxy: tabular patterns related pattern — Use this MOC to choose corpus-grounded Galaxy tabular transformation patterns.
  • Tabular: compute a new column related pattern — Append, insert, or replace computed columns with column_maker (Add_a_column1), using a shared input-typing policy and explicit failure handling.
  • Tabular: cut and reorder columns related pattern — Use Cut1 with a comma-separated cN list to project — and reorder — columns. Listing out of order is the canonical reorder idiom.
  • Tabular: filter rows by column value related pattern — Use Filter1 with a Python expression over cN columns to drop rows. Highest-frequency tabular row filter in IWC.
  • Tabular: filter rows by regex related pattern — Use tp_grep_tool for whole-line regex row filters on tabular input. Grep1 is the legacy alternative.
  • Tabular: group and aggregate related pattern — Group tabular rows by one-based key columns, sort when needed, and choose Datamash operations and header settings from the intended result.
  • Tabular: join on key related pattern — Join tabular files by key with explicit matched-row, missing-value, header, and duplicate-key policies.
  • Iwc Tabular Operations Survey related note — Corpus survey of tabular tools and operations across IWC workflows. Evidence for the operation pattern hierarchy on row/column data manipulation.
  • Nextflow-to-Galaxy channel shape mapping related note — Maps common Nextflow channel, tuple, and path shapes to Galaxy dataset and collection shapes.