0

I am writing a Perl based application that converts an SQLite database into an Excel workbook and back again. It works as is, but is missing one small piece. I do not know how to determine if the UNIQUE constraint has been set for a specific column.

To get a list of tables in a database, I use:

select name from sqlite_master 
  where type = 'table' 
  and name <> 'sqlite_sequence' order by name;

Then to get column and constraint information for each table, I do:

PRAGMA table_info($TableName);

This tells me everything I need to know except if a column has the UNIQUE constraint enabled.

In case this is not clear, here is a trivial example. Suppose I create a database table by doing this:

CREATE TABLE DATA 
(
    ID integer primary key, 
    Invoice integer unique, 
    Product varchar, 
    Comment varchar
);

I want to know how I can subsequently interrogate the SQLite database table created in this manner to determine which columns have the UNIQUE constraint set. In this case, it would be the Invoice column.

Any suggestions?

4

3 回答 3

2

You need to use a the PRAGMA index_list statement.

This subroutine determines the value of the unique attribute, given a database handle and a table and column name.

sub column_unique {
  my ($dbh, $table, $column) = @_;
  my $sth = $dbh->prepare("PRAGMA index_list($table)");
  $sth->execute;
  my $rec = $sth->fetchall_hashref('name');
  return $rec->{$column} && $rec->{$column}{unique};
}

If the column appears in the index_list pragma for the table, the value of the unique attribute (either '0' or '1') is returned. If not then undef is returned. This allows calls like

if (column_unique($dbh, 'DATA', 'Invoice')) { ... }

Edit

My apologies, my first answer was wrong. SQLite allows only indexes to be declared unique, and those indexes can be multi-column combinations. This revised subroutine looks at the composition of each unique index for the table and checks whether the given column is all or part of it.

This isn't very satisfactory, as being a part of a unique index doesn't say much about the column itself, but any improvement would depend on what you want to use the information for.

sub column_unique {

  my ($dbh, $table, $column) = @_;

  my $sth = $dbh->prepare("PRAGMA index_list($table)");
  $sth->execute;
  my $list = $sth->fetchall_hashref('name');

  foreach my $index (keys %$list) {

    next unless $list->{$index}{unique};

    my $sth = $dbh->prepare("PRAGMA index_info($index)");
    $sth->execute;
    my $info = $sth->fetchall_hashref('name');

    return 1 if $info->{$column};
  }

  return 0;
}
于 2012-05-18T16:09:40.453 回答
0

Run this query:

SELECT
  m.tbl_name AS table_name,
  il.name AS key_name,
  ii.name AS column_name
FROM 
  sqlite_master AS m, 
  pragma_index_list(m.name) AS il, 
  pragma_index_info(il.name) AS ii 
WHERE 
  m.type = 'table' AND 
  il.origin = 'u' 
ORDER BY table_name, key_name, ii.seqno;

This should produce something like:

table_name | key_name                | column_name
-----------+-------------------------+------------
data       | sqlite_autoindex_data_1 | Invoice
于 2021-01-22T13:07:00.243 回答
0

I needed the same and I thinks this is the easiest solution:

SELECT (SELECT name FROM pragma_index_info(pmi.name)) AS UniqueColumn

FROM pragma_index_list(tablename) AS pmi

It works for both the unique constraint and the primary key constraint, which is also an implicit unique constraint.

于 2021-02-16T14:46:04.963 回答