C, PHP, VB, .NET

Дневникът на Филип Петров


* Агрегатни функции

Публикувано на 17 март 2009 в раздел Бази от Данни.

Преди да започнем, нека разгледаме следната база от данни:

База Данни за банка

Ето и заявките за създаване на тази база от данни и да вмъкнем произволни данни в нея:

CREATE DATABASE `banks`;

CREATE TABLE `banks`.`banks` (
	`code` INT NOT NULL AUTO_INCREMENT ,
	`name` VARCHAR( 255 ) NOT NULL ,
	`country` VARCHAR( 255 ) NOT NULL ,
	PRIMARY KEY ( `code` )
) ENGINE = InnoDB;

CREATE TABLE `banks`.`branches` (
	`id` TINYINT NOT NULL AUTO_INCREMENT ,
	`name` VARCHAR( 255 ) NOT NULL ,
	`address` VARCHAR( 255 ) NOT NULL ,
	`bank_code` INT NOT NULL ,
	PRIMARY KEY ( `id` ) ,
	FOREIGN KEY ( `bank_code` )
		REFERENCES `banks`.`banks`( `code` )
		ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB;

CREATE TABLE `banks`.`employees` (
	`id` INT NOT NULL AUTO_INCREMENT ,
	`name`  VARCHAR( 255 ) NOT NULL ,
	`branch_id` TINYINT NOT NULL,
	PRIMARY KEY ( `id` ),
	FOREIGN KEY ( `branch_id` )
		REFERENCES `banks`.`branches`( `id` )
		ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB;

CREATE TABLE `banks`.`customers` (
	`id` INT NOT NULL AUTO_INCREMENT ,
	`name` VARCHAR( 255 ) NOT NULL ,
	`address` VARCHAR( 255 ) NULL DEFAULT NULL ,
	`bank_mgr` INT NULL ,
	PRIMARY KEY ( `id` ) ,
	FOREIGN KEY ( `bank_mgr` )
		REFERENCES `banks`.`employees`( `id` )
) ENGINE = InnoDB;

CREATE TABLE `banks`.`accounts` (
	`id` INT NOT NULL AUTO_INCREMENT ,
	`amount` DECIMAL( 9,2 ) NOT NULL ,
	`type` TINYINT NOT NULL,
	`branch_id` TINYINT NOT NULL,
	`customer_id` INT NOT NULL,
	PRIMARY KEY ( `id` ),
	FOREIGN KEY ( `branch_id` )
		REFERENCES `banks`.`branches`( `id` )
		ON DELETE CASCADE ON UPDATE CASCADE,
	FOREIGN KEY ( `customer_id` )
		REFERENCES `banks`.`customers`( `id` )
		ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB;

USE banks;

INSERT INTO `banks` (`code` ,`name` ,`country`)
VALUES 	( NULL , 'Bulbank', 'Bulgaria' ),
	( NULL , 'Wells Fargo', 'USA' ),
	( NULL , 'Bank of America', 'USA' ),
	( NULL , 'Societe General', 'France' );

INSERT INTO `branches` (`id` ,`name` ,`address`, `bank_code`)
VALUES 	( NULL , 'Serdica', 'Sofia centar', 1 ),
	( NULL , 'Slatina', 'Sofia Geo Milev', 1 ),
	( NULL , 'Manhattan', 'Manhattan, New York', 2 ),
	( NULL , 'LA', 'Los Angeles', 3 ),
	( NULL , 'Paris', 'Paris', 4 ),
	( NULL , 'Marseilles', 'Marseilles', 4 );

INSERT INTO `employees` (`id` ,`name` , `branch_id`)
VALUES	( NULL , 'Ivan Ivanov', 1 ),
	( NULL , 'Ivan Stoianov', 1 ),
	( NULL , 'Mihail Zahariev', 1 ),
	( NULL , 'Milen Stoilov', 2 ),
	( NULL , 'Svilen Petrov', 2 ),
	( NULL , 'Ilian Stoianov', 2 ),
	( NULL , 'Petar Petrov', 2 ),
	( NULL , 'Jimmy Carter', 3 ),
	( NULL , 'John Smith', 3 ),
	( NULL , 'Mary Jane', 3 ),
	( NULL , 'James Pitt', 4 ),
	( NULL , 'Francoa Dupres', 5 ),
	( NULL , 'Alfonso Levi', 6 );

INSERT INTO `customers` (`id` ,`name` , `bank_mgr`)
VALUES	( NULL , 'Todor Ivanov', 1 ),
	( NULL , 'Petko Stoianov', 1 ),
	( NULL , 'Neno Nenov', 2 ),
	( NULL , 'Mariana Zaharieva', 3 ),
	( NULL , 'Elica Zaharieva', 3 ),
	( NULL , 'Atanas Petrov', 4 ),
	( NULL , 'Ivan Ivanov', 4 ),
	( NULL , 'Zlatomir Petrov', 4 ),
	( NULL , 'Mihail Ivchev', 5 ),
	( NULL , 'Todor Shtilianov', 6 ),
	( NULL , 'Ivailo Ivanov', 7 ),
	( NULL , 'George Lucas', 8 ),
	( NULL , 'George Harison', 8 ),
	( NULL , 'Michael Jackson', 8 ),
	( NULL , 'Tony Martin', 8 ),
	( NULL , 'Tony McCarter', 10 ),
	( NULL , 'Alexander Smith', 11 ),
	( NULL , 'Maria Smith', 11 ),
	( NULL , 'Alain Delrick', 12 ),
	( NULL , 'Devry Henry', 12 ),
	( NULL , 'Lenard Renne', 12 ),
	( NULL , 'Fontaine Rupert', 13 );

INSERT INTO `accounts` (`id` ,`amount` , `type` , `customer_id`, `branch_id`)
VALUES	( NULL , 156.38, 2, 1, 1 ),
	( NULL , 136.22, 1, 2, 1 ),
	( NULL , 42.98, 1, 3, 1 ),
	( NULL , 1236.33, 1, 4, 1 ),
	( NULL , 211.98, 2, 5, 1 ),
	( NULL , 1200.00, 2, 6, 2 ),
	( NULL , 133.48, 1, 7, 2 ),
	( NULL , 256.41, 2, 8, 2 ),
	( NULL , 1331.50, 2, 9, 2 ),
	( NULL , 116.88, 2, 10, 2 ),
	( NULL , 200.91, 1, 10, 2 ),
	( NULL , 99.18, 1, 11, 2 ),
	( NULL , 6712.52, 1, 12, 3 ),
	( NULL , 12000.56, 1, 12, 3 ),
	( NULL , 322.99, 2, 12, 3 ),
	( NULL , 991.63, 1, 13, 3 ),
	( NULL , 559.32, 2, 14, 3 ),
	( NULL , 680.13, 1, 15, 3 ),
	( NULL , 532.57, 1, 15, 3 ),
	( NULL , 402.26, 1, 16, 3 ),
	( NULL , 1536.91, 2, 17, 4 ),
	( NULL , 14921.43, 1, 18, 4 ),
	( NULL , 3910.50, 1, 19, 5 ),
	( NULL , 231.37, 1, 20, 5 ),
	( NULL , 7236.60, 1, 21, 5 ),
	( NULL , 2226.63, 2, 21, 5 ),
	( NULL , 500.00, 2, 22, 6 );

Агрегатните функции ни позволяват да обединим (групираме) дадено множество и да направим някакво обобщение за него.

Ще ви дадем няколко прости примера:

1. Изкарайте броят на въведените банки в базата от данни:

mysql> SELECT COUNT(*) FROM banks;
+----------+
| COUNT(*) |
+----------+
|        4 |
+----------+

Функцията COUNT() в случая преброи броят редове на таблицата banks.

2. Изведете най-голямата сума на акаунт в базата от данни:

mysql> SELECT MAX(amount) FROM accounts;
+-------------+
| MAX(amount) |
+-------------+
|    14921.43 |
+-------------+

Функцията MAX() намери най-голямата стойност в колоната и я изведе на екрана.

3. Изведете най-малката сума на акаунт в базата от данни от банков клон с id=2:

mysql> SELECT MIN(amount)
FROM accounts
WHERE branch_id=2;
+-------------+
| MIN(amount) |
+-------------+
|       99.18 |
+-------------+

Тук очевидно MIN намери най-малката стойност в колоната “amount” на тези редове от таблица “accounts”, за които branch_id е равно на 2.

4. Намерете средното аритметично на сумите на всички акаунти на Bulbank:

mysql> SELECT AVG(amount)
FROM accounts
WHERE branch_id IN(
	SELECT id
	FROM branches
	WHERE bank_code = (
		SELECT code
		FROM banks
		WHERE name = 'Bulbank'
	)
);
+-------------+
| AVG(amount) |
+-------------+
|  426.854167 |
+-------------+
1 row in set (0.00 sec)

Ясно е, че AVG() сумира стойностите в колоната по редове и разделя сумата на техния брой.

5. Изведете името и общата сума пари, която притежава клиент с id=12, във всички негови акаунти:

mysql> SELECT customers.name, SUM(accounts.amount)
FROM customers JOIN accounts ON customers.id = accounts.customer_id
WHERE customers.id = 12;
+--------------+----------------------+
| name         | SUM(accounts.amount) |
+--------------+----------------------+
| George Lucas |             19036.07 |
+--------------+----------------------+
1 row in set (0.00 sec)

Функцията SUM() връща сумата на върнатите редове.

В следващата статия ще разгледаме една по-силна техника – групиране на таблици по дадена колона.

 



7 коментара


  1. Йордан каза:

    Относно горната ER-диаграма, искам да ви попитам колко характеризиращи обекта може да има в една ER-диаграма и възможно ли е например account да е характеризиращ обект на customers?

  2. Да, може. Разликата между характеризиращ и обикновен обект практически не е никаква в реалното изпълнение на задачата. В общи линии се използват за пригледност.

  3. TU каза:

    Защо аccount e вързано и с branches, и с customer? Не трябва ли да е само с customer? И какво означава съкращението mgr?

  4. Нарочно е направен този „двоен път“, за да бъдат демонстрирани някои проблеми с дизайна.

    „mgr“ = „manager“ или „личен мениджър“ за този клиент.

  5. Заявки 3. и 4. няма да работят. Ще трябва да се пренапишат. Впрочем ще е добро упражнение.

  6. TU каза:

    А ако връзката с branches се прекъсне, ще бъде ли грешка?

  7. Ivo каза:

    Може би е хубаво да се спомене, че ако търсим средно аритметичната стойност на колона, която съдържа NULL стойности, те не се отчитат когато се дели на общия брой. Примерно:

    CREATE TABLE numbers(
    id INT AUTO_INCREMENT,
    number INT,
    PRIMARY KEY(id)
    );

    INSERT INTO numbers(number) VALUES
    (5),
    (5),
    (NULL);

    SELECT AVG(number) FROM numbers; – ще върне 5, защото сумата се дели на броя на стойностите, които не са NULL

Добави коментар

Адресът на електронната поща няма да се публикува


*