按日期的动态表名称

时间:2016-06-10 15:46:17

标签: postgresql postgresql-8.2

所以我有需要每晚生成的表格。作为一个例子,我有foo_01jan16,foo_02jan2016,foo_03jan2016等表。此外,我在我每天运行的其他查询中引用这些表。但是,查找和替换似乎效率低下。我想要做的是自动化这个过程。我想做点什么:

table_date()

然后在查询中我可以参考 CREATE TABLE table_date() AS SELECT * FROM base_table WHERE date <= current_date; SELECT * FROM table_date() LIMIT 10; ?即。

private void DoIt()
{
    const long m = 101;
    const long x = 387420489; // must be coprime to m

    var multInv = MultiplicativeInverse(x, m);

    var nums = new HashSet<long>();
    for (long i = 0; i < 100; ++i)
    {
        var encoded = i*x%m;
        var decoded = encoded*multInv%m;
        Console.WriteLine("{0} => {1} => {2}", i, encoded, decoded);
        if (!nums.Add(encoded))
        {
            Console.WriteLine("Duplicate");
        }
    }
}

private long MultiplicativeInverse(long x, long modulus)
{
    return ExtendedEuclideanDivision(x, modulus).Item1%modulus;
}

private static Tuple<long, long> ExtendedEuclideanDivision(long a, long b)
{
    if (a < 0)
    {
        var result = ExtendedEuclideanDivision(-a, b);
        return Tuple.Create(-result.Item1, result.Item2);
    }
    if (b < 0)
    {
        var result = ExtendedEuclideanDivision(a, -b);
        return Tuple.Create(result.Item1, -result.Item2);
    }
    if (b == 0)
    {
        return Tuple.Create(1L, 0L);
    }
    var q = a/b;
    var r = a%b;
    var rslt = ExtendedEuclideanDivision(b, r);
    var s = rslt.Item1;
    var t = rslt.Item2;
    return Tuple.Create(t, s - q*t);
}

这样的事情。我正在使用postgreSQL 8.2。

由于

1 个答案:

答案 0 :(得分:1)

No, you can't do that because PG needs a string literal for the table name, not some expression. As usual, there is a work-around in PG, in the form of a dynamic query in a PL/pgSQL function.

First you have to create the table and populate it:

CREATE FUNCTION todays_data() RETURNS void AS $$
BEGIN
  EXECUTE 'CREATE TABLE foo_' || to_char(CURRENT_DATE, 'DDMONYYYY') ||
          ' AS SELECT * FROM base_table WHERE date <= CURRENT_DATE';
END;
$$ LANGUAGE plpgsql;

You should call this function once per day: SELECT todays_data();.

For the queries you need to make a function for each of them, using a CURSOR. This is rather inefficient by today's standards, but PG 8.2 does not have support for RETURN NEXT QUERY which would solve the below function with a single statement. So, the hard way:

CREATE FUNCTION someday_query1(dt date) RETURNS SETOF base_table AS $$
DECLARE
  cur refcursor;
  rec base_table%ROWTYPE;
BEGIN
  OPEN cur FOR EXECUTE 'SELECT * FROM foo_' || to_char(dt, 'DDMONYYYY') ||
                       ' WHERE some_condition';
  FETCH cur INTO rec;
  WHILE FOUND LOOP
    RETURN NEXT rec;
    FETCH cur INTO rec;
  END LOOP;
  CLOSE cur;
END;
$$ LANGUAGE plpgsql STRICT;

Then you can call the queries like so:

SELECT * FROM someday_query1(CURRENT_DATE);

or

SELECT * FROM someday_query1('2016-01-23');