PostgreSQL的相同触发器函数可以在INSERT上更新到不同的表中(使用相同的模式)

时间:2019-01-12 12:55:58

标签: sql postgresql triggers

我有100个具有相同模式的表,并且我有一个触发函数,只要将数据插入到该表中就更新一些列。

表架构:

public class FirebaseAuthentication {

private Activity mContext;
private FirebaseAuth mAuth;
private OnComplete mOnComplete;

public FirebaseAuthentication(Activity context) {
    mContext = context;
    mAuth = FirebaseAuth.getInstance();
}

public void registerUserWithEmailandPassword(String username, String password) {
    mAuth.createUserWithEmailAndPassword(username, password).addOnCompleteListener(mContext, new MyCompleteListener());
}

public void loginUserWithEmailandPassword(String username, String password) {
    mAuth.signInWithEmailAndPassword(username, password).addOnCompleteListener(mContext, new MyCompleteListener());
}

public FirebaseUser getCurrentUser() {
    FirebaseUser user = mAuth.getCurrentUser();
    return user;
}

public void signOutUser() {
    mAuth.signOut();
    mContext.startActivity(new Intent(mContext, LoginActivity.class));
}

public User getUserProfile() {
    FirebaseUser firebaseUser = getCurrentUser();
    User user = new User();
    if (firebaseUser != null) {
        user.setName(firebaseUser.getDisplayName());
        user.setEmail(firebaseUser.getEmail());
        user.setPhotoUrl(firebaseUser.getPhotoUrl());
        user.setUid(firebaseUser.getUid());
        user.setVerifiedEmail(firebaseUser.isEmailVerified());
    }
    return user;
}

public void updateUserName(String name) {
    FirebaseUser firebaseUser = getCurrentUser();
    if (firebaseUser != null) {
        UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
                .setDisplayName(name)
                .build();
        firebaseUser.updateProfile(profileUpdates).addOnCompleteListener(new MyCompleteListener());
    }
}

public void updateProfilePhoto(String uri) {
    FirebaseUser firebaseUser = getCurrentUser();
    if (firebaseUser != null) {
        UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
                .setPhotoUri(Uri.parse(uri))
                .build();
        firebaseUser.updateProfile(profileUpdates).addOnCompleteListener(new MyCompleteListener());
    }
}

public void updateEmailAddress(String email) {
    FirebaseUser firebaseUser = getCurrentUser();
    if (firebaseUser != null) {
        firebaseUser.updateEmail(email).addOnCompleteListener(new MyCompleteListener());
    }
}

public void sendVerificationMail() {
    FirebaseUser firebaseUser = getCurrentUser();
    firebaseUser.sendEmailVerification().addOnCompleteListener(new MyCompleteListener());
}

public void changePassword(String password) {
    FirebaseUser user = getCurrentUser();
    if (user != null) {
        String newPassword = password;
        user.updatePassword(newPassword).addOnCompleteListener(new MyCompleteListener());
    }
}

public void sendResetLink(String email) {
    FirebaseAuth auth = FirebaseAuth.getInstance();
    String emailAddress = email;
    auth.sendPasswordResetEmail(emailAddress).addOnCompleteListener(new MyCompleteListener());
}

public void deleteAccount() {
    FirebaseUser user = getCurrentUser();
    if (user != null) {
        user.delete().addOnCompleteListener(new MyCompleteListener());
    }
}

public interface OnComplete {
    void onSuccessListner();
    void onFailureListner(String message);
}

public void setOnCompleteListener(OnComplete onCompleteListener) {
    mOnComplete = onCompleteListener;
}

private class MyCompleteListener implements OnCompleteListener {

    @Override
    public void onComplete(@NonNull Task task) {
        if (task.isSuccessful()) {
            mOnComplete.onSuccessListner();
        }else {
            mOnComplete.onFailureListner(task.getException().getLocalizedMessage());
        }
      }
   }
}

触发功能:

CREATE TABLE symbol_daily_ohlc (
 cdate date,
 open numeric(8,2),
 high numeric(8,2),
 low numeric(8,2),
 close numeric(8,2),
 sma8 numeric(8,2)
);

表上的触发器设置:

create or replace function update_sma8() RETURNS TRIGGER AS
$$
BEGIN
UPDATE symbol_daily_ohlc d SET sma8 = s.simple_mov_avg 
FROM
(
 SELECT  sec.cdate,AVG(sec.close)  
 OVER(ORDER BY sec.cdate ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) AS 
 simple_mov_avg FROM symbol_daily_ohlc sec
)s where s.cdate = NEW.cdate  --The newly inserted cdate
 AND d.cdate = s.cdate;   
RETURN NULL;
END $$ language plpgsql;

对于给定的表(即symbol_daily_ohlc),此方法效果很好。我想使用相同的触发函数,即update_sma8()与具有相同模式的任何表一起使用(我不想为不同的表重写相同的函数)。

我尝试用TG_TABLE_NAME替换表名(即symbol_daily_ohlc),但这不起作用-引发错误。那怎么办呢?

参考:SQL trigger function to UPDATE daily moving average upon INSERT

2 个答案:

答案 0 :(得分:0)

我认为您可能必须使用SQL来生成SQL,然后运行生成的SQL。像这样:

select CONCAT('create or replace function update_sma8() RETURNS TRIGGER AS
  $$
  BEGIN
  UPDATE ', table_name, '  d SET sma8 = s.simple_mov_avg 
  FROM
  (
   SELECT  sec.cdate,AVG(sec.close)  
   OVER(ORDER BY sec.cdate ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) AS 
   simple_mov_avg FROM ', table_name, '
  )s where s.cdate = NEW.cdate  --The newly inserted cdate
  AND d.cdate = s.cdate;   
  RETURN NULL;
  END $$ language plpgsql;
') from information_schema.tables

但实际上,您应该考虑戈登的建议(以及我的跟进),并将所有数据放回到一张表中:

SELECT CONCAT('INSERT INTO all_hist SELECT ''', table_name, ''', t.* FROM ', table_name) FROM information_schema.tables

这将生成一堆将所有表数据放入all_hist的sql,该表应该具有与其他数千个表相同的架构,除了附加的列“ symbol”或其他内容。.

如果您确实需要,可以使用类似的技巧来创建一堆视图以重新创建千位表方法。

答案 1 :(得分:0)

您可以使用相同的过程来执行并返回所有表的触发器,但是不能为所有表使用相同的触发器。

这是一个动态创建带有表名后缀(使用EXECUTE format的触发器)的块

DO $$
declare
tabs RECORD;
BEGIN
for tabs IN
(select table_name,table_schema
   from information_schema.tables where table_name 
   like 'symbol_daily_ohlc%' 
  -- and table_schema like '%'
) LOOP
EXECUTE format('CREATE TRIGGER check_update_%I
    AFTER INSERT ON %I.%I
    FOR EACH ROW
EXECUTE PROCEDURE update_sma8()',tabs.table_name,
 tabs.table_schema
,tabs.table_name);
END LOOP;
END $$;

这是您的触发器,它从TG_TABLE_NAME

动态获取表名
create or replace function update_sma8() RETURNS TRIGGER AS
$$
 BEGIN

EXECUTE format ('UPDATE %I d SET sma8 = s.simple_mov_avg 
FROM
(
 SELECT  sec.cdate,AVG(sec.close)  
   OVER(ORDER BY sec.cdate ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) AS 
    simple_mov_avg FROM %I sec
)s where s.cdate = %L  --The newly inserted cdate
     AND d.cdate = s.cdate',TG_TABLE_NAME,TG_TABLE_NAME,NEW.cdate);   
RETURN NULL;

END $$ language plpgsql;

Demo

正如其他人所建议的那样,拥有多个具有相同结构的表不是一个好主意。您应该考虑将它们合并到一个表中。