您的架构绝对令人恐惧:
24 ***_status text YES
25 ***_status text YES
26 ***_status text YES
27 ***_status text YES
28 ***_status text YES
29 ***_status text YES
我认为被屏蔽***
的地方类似于出版物/通讯/等的名称。
您需要阅读有关数据规范化的信息,否则您将遇到一个不断增长的问题,直到您达到PostgreSQL 的行大小限制。
由于每个感兴趣的项目都在不同的列中,因此使用现有模式解决此问题的唯一方法是使用 PL/PgSQL 的EXECUTE format(...) USING ...
. 您可能认为这只是一个临时选项,但这有点像使用打桩机将方钉塞入圆孔,因为锤子不够大。
SQL 中没有列名通配符,例如*_status
or %_status
。列是行的固定组成部分,具有不同的类型和含义。每当您发现自己想要这样的东西时,这表明您的设计需要重新考虑。
我不打算写一个例子,因为(a)这是一家电子邮件营销公司,(b)“混淆”模式对于任何类型的测试都是完全不可用的,如果没有大量的手动工作重写它。(将来,请为您的虚拟数据提供CREATE TABLE
和INSERT
声明,或者更好的是http://sqlfiddle.com/)。format
通过快速搜索 Stack Overflow,您将在 PL/PgSQL 中找到许多动态 SQL 的示例 - 以及有关如何通过正确使用来避免由此产生的 SQL 注入风险的警告。我以前写过一堆。
请为了您的理智和其他需要在此系统上工作的人的理智,规范化您的模式。
您可以在规范化表上创建一个视图以呈现旧结构,让您有时间调整您的应用程序。通过更多的工作,您甚至可以定义DO INSTEAD
视图触发器(较新的 Pg 版本)或RULE
(较旧的 Pg 版本)以使视图可更新和可插入,因此您的应用程序甚至无法判断任何内容已更改 - 尽管这是为了性能成本,所以如果可能的话,最好调整应用程序。
从这样的事情开始:
CREATE TABLE subscriber (
id serial primary key,
email_address text not null,
-- please read http://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/
-- for why I merged "fname" and "lname" into one field:
realname text,
-- Store birth month/year as a "date" with a "CHECK" constraint forcing it to be the 1st day
-- of the month. Much easier to work with.
birthmonth date,
CONSTRAINT birthmonth_must_be_day_1 CHECK ( extract(day from birthmonth) = 1),
postcode text,
-- Congratulations! You made "gender" a "text" field to start with, you avoided
-- one of the most common mistakes in schema design, the boolean/binary gender
-- field!
gender text,
-- What's MSO? Should have a COMMENT ON...
mso text,
source text,
-- Maintain these with a trigger. If you want modified to update when any child record
-- changes you can do that with triggers on subscription and reducedfreq_subscription.
created_on timestamp not null default current_timestamp,
last_modified timestamp not null,
-- Use the native PostgreSQL UUID type, after running CREATE EXTENSION "uuid-ossp";
uuid uuid not null,
uuid2 uuid not null,
brand text,
-- etc etc
);
CREATE TABLE reducedfreq_subscription (
id serial primary key,
subscriber_id integer not null references subscriber(id),
-- Suspect this was just a boolean stored as text in your schema, in which case
-- delete it.
reducedfreqsub text,
reducedfreqpref text,
-- plural, might be a comma list? Should be in sub-table ("join table")
-- if so, but without sample data can only guess.
reducedfreqtopics text,
-- date can be NOT NULL since the row won't exist unless they joined
reducedfreq_datejoined date not null,
reducedfreq_dateunsub date
);
CREATE TABLE subscription (
id serial primary key,
subscriber_id integer not null references subscriber(id),
sub_name text not null,
status text not null,
datejoined date not null,
dateunsub date
);
CREATE TABLE subscriber_activity (
last_click timestamptz,
last_open timestamptz,
last_hardbounce timestamptz,
last_softbounce timestamptz,
last_successful_mailing timestamptz
);