from typing import List


def sql_insert_rows_not_in_table(insert_table_name: str, reference_table_name: str, id_column_names: List[str],
                                 column_names: List[str]) -> str:
    """Create SQL to insert rows into a table, but only if those rows don't already exist in a reference table."""
    insert_table_cols = ",".join(["{tbl}.{col}".format(tbl=insert_table_name, col=col)
                                  for col in id_column_names])
    reference_table_cols = ",".join(["{tbl}.{col}".format(tbl=reference_table_name, col=col)
                                     for col in id_column_names])
    # The left join will give nulls for the joined table when no matches are found.
    # We use '(tuple) is null' to see if all columns (values in the tuple) are null.
    select_sql = "SELECT {ref}.* FROM {ref} LEFT JOIN {ins} ON ({ins_cols}) = ({ref_cols}) WHERE ({ins_cols}) is NULL"\
        .format(ref=reference_table_name, ins=insert_table_name,
                ins_cols=insert_table_cols, ref_cols=reference_table_cols)
    columns_sql = ','.join(column_names)

    insert_sql = "INSERT INTO {ins}({cols}) ({select_sql}) RETURNING NULL;".format(
        ins=insert_table_name, cols=columns_sql, select_sql=select_sql)
    return insert_sql