sql >> Databáze >  >> RDS >> Mysql

Jak mohu přidat sloupec, který se zvyšuje na jiný sloupec ve stejné tabulce?

Moje nejlepší rada pro vás je, nedělejte to. Ukládání informací, které lze odvodit z jiných informací v databázi, je obecně považováno za velmi špatný návrh a pokus spoléhat se na pořadí řádků v databázi je jistá cesta k šílenství.

Zde je první průchod normalizací vaší tabulky:

-- Table: teams

-- DROP TABLE teams;

CREATE TABLE teams
(
  team_id character(3) primary key,
  team_name varchar(255),
  team_city varchar(255)
) engine=innodb;

-- Table: starting_pitchers_game_log

-- DROP TABLE starting_pitchers_game_log;

CREATE TABLE starting_pitchers_game_log
(
  pitcher_id character(10) NOT NULL,
  game_date date NOT NULL,
  opposing_team character(3),
  game_seq integer NOT NULL,
  outcome character(1),
  innings_pitched real,
  bfp integer,
  hits integer,
  runs integer,
  errors integer,
  homeruns integer,
  bb integer,
  k integer,
  ibb integer,
  hbp integer,
  wp integer,
  balks integer,
  CONSTRAINT starting_pitcher_log_pk
      PRIMARY KEY (pitcher_id , game_date , game_seq ),
  CONSTRAINT team_fk FOREIGN KEY (opposing_team)
      REFERENCES teams (team_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
) engine=innodb;

(Nesleduji baseball, takže jsem mohl jen odhadovat názvy některých sloupců.) Všimněte si, že year_id , month_id a day_id sloupce jsou pryč, protože tyto hodnoty lze znovu vytvořit z game_date sloupec, jak jsem uvedl v komentářích. Také vaše game_id sloupec je pryč; toto lze znovu vytvořit zřetězením opposing_team , game_date a game_seq (předpokládám, že to zohledňuje dvojitá záhlaví atd.) Také jsem převedl W a L do jednoho sloupce, který má obsahovat hodnoty „W“ (výhra), „L“ (prohra) a „T“ (remíza).

teams tabulka poskytuje vyhledávací tabulku pro 3znaková ID týmu. Lze jej rozšířit tak, aby obsahoval jakákoli další týmová data, která chcete. (Všimněte si, že to má popisovat tým samotný; týmové činnosti by šlo do jiné tabulky.)

Abychom odpověděli na vaši otázku týkající se „omezení“ klauzulí, první z nich (CONSTRAINT starting_pitcher_log_pk a odsazený řádek pod ním) určuje, že zřetězení těchto tří sloupců slouží jako primární jedinečný identifikátor pro každý řádek v tabulce. Druhý (CONSTRAINT team_fk FOREIGN KEY (opposing_team) a odsazené řádky pod tím) znamenají, že pro hodnotu, která má být umístěna do opposing_team sloupec, který musí již existovat v teams.team_id sloupec; nemůžete hrát proti týmu, který neexistuje.

Nyní pracujte na skutečné odpovědi na vaši původní otázku. Nejlepším řešením, které jsem mohl na MySQL vymyslet, byla stírací tabulka a uložená procedura:

-- Table: ip_subtotal

-- DROP TABLE ip_subtotal;

CREATE TABLE ip_subtotal
(
  pitcher_id char(10) NOT NULL,
  game_date date NOT NULL,
  game_seq int(11) NOT NULL,
  innings_pitched double,
  ip_total double DEFAULT '0.0',
  CONSTRAINT ip_subtotal_pk
      PRIMARY KEY (pitcher_id , game_date , game_seq )
) ENGINE=InnoDB;

A uložená procedura:

------------------------------------------------------------------------------    --
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$

CREATE PROCEDURE accumulate_innings()
BEGIN
    DECLARE pit_id CHAR(10);
    DECLARE gdate DATE;
    DECLARE seq INT;
    DECLARE in_pit REAL;
    DECLARE accum REAL;
    DECLARE prev_year YEAR(4);
    DECLARE end_of_cursor BOOLEAN;

    DECLARE c1 CURSOR FOR
        SELECT pitcher_id, game_date, game_seq, innings_pitched
            FROM ip_subtotal
            ORDER BY pitcher_id, game_date, game_seq;

    DECLARE CONTINUE HANDLER FOR NOT FOUND
        SET end_of_cursor := TRUE;

    TRUNCATE TABLE ip_subtotal;
    INSERT INTO ip_subtotal
        SELECT pitcher_id, game_date, game_seq, innings_pitched, 0.0
            FROM starting_pitchers_game_log;

    SET prev_year := 0;
    OPEN c1;

    fetch_loop: LOOP
        FETCH c1 INTO pit_id, gdate, seq, in_pit;
        IF end_of_cursor THEN
            LEAVE fetch_loop;
        END IF;
        IF YEAR(gdate) != prev_year THEN
            SET accum := 0.0;
            SET prev_year := YEAR(gdate);
        END IF;
        SET accum := accum + in_pit;
        UPDATE ip_subtotal
            SET ip_total = accum
            WHERE pitcher_id = pit_id
              AND game_date = gdate
              AND game_seq = seq;
    END LOOP;
    CLOSE c1;
END

Tento postup vymaže tabulku ip_subtotal , naplní jej z hlavního stolu a poté vygeneruje průběžný součet pro nahozené směny. K resetování akumulátoru na začátku roku také využívá jednoduchou ovládací přestávku. Po spuštění procedury spuštěním

CALL accumulate_innings();

můžete zadat dotaz na ip_subtotal stůl nebo jej připojte zpět k starting_pitchers_game_log podle potřeby.

Postup by mohl být také rozšířen tak, aby akceptoval počáteční a koncové datum; Nechám to jako cvičení pro čtenáře.

Snad to pomůže; bylo to zajímavé a donutilo mě to naučit se trochu MySQL.




  1. Co je nového v MySQL Galera Cluster 4.0

  2. Nejlepší postup pro implementaci zabezpečené databáze pro zařízení Android

  3. Ukládání obrázků v souborovém systému jako soubory nebo v poli databáze BLOB jako binární soubory

  4. Oracle Pivot dotaz poskytuje sloupce s uvozovkami kolem názvů sloupců. Co?