2014-02-22 2 views
1

Я бы хотел показать только последние 5 транзакций для каждого типа учетной записи из таблицы «Банк». Структура таблицы банка является:Что представляет собой более сжатый способ написать самостоятельное соединение SQL

CREATE TABLE bank(
bnk_id INT(11) AUTO_INCREMENT PRIMARY KEY NOT NULL, 
...... 
bnk_acc_id INT(11) NOT NULL 
) 

, как я получил его на работу сейчас, имея для создания временных таблиц следующим

CREATE TABLE B1 AS 
SELECT bnk_id FROM bank WHERE bnk_acc_id=1 ORDER BY bnk_date DESC LIMIT 5; 

CREATE TABLE B2 AS 
SELECT bnk_id FROM bank WHERE bnk_acc_id=2 ORDER BY bnk_date DESC LIMIT 5; 

Тогда я бы выполнить следующий запрос

SELECT * 
    FROM bank 
WHERE bnk_id IN (SELECT * FROM B1) 
    OR bnk_id IN (SELECT * FROM B2) 

Кстати, существует 6 разных типов счетов (представлено в таблице как bnk_acc_id) Я бы подумал, что есть более эффективный способ написать thi s SQL. Пожалуйста, пришлите мне совет.

ответ

3

Это устраняет дополнительную временную таблицу.

SELECT * FROM bank WHERE bnk_acc_id=1 ORDER BY bnk_date DESC LIMIT 5; 
UNION ALL 
SELECT * FROM bank WHERE bnk_acc_id=2 ORDER BY bnk_date DESC LIMIT 5; 
0

Вам необходимо разбить свои данные на группы строк для каждой учетной записи. Затем вы можете использовать эти сгруппированные данные для извлечения первого n из каждой группы. Это означает, что вам не нужно указывать идентификаторы учетных записей в каждом выборе.

Ниже приведен пример с использованием временной таблицы для хранения некоторых примеров для Вас данные:

CREATE TABLE [#bank] 
(
    bnk_id INT IDENTITY(1, 1) PRIMARY KEY NOT NULL, 
    bnk_acc_id INT NOT NULL, 
    bnk_date datetime NOT NULL 
) 

INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES (1, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(1, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(1, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(1, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(1, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(1, getutcdate()) 

INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(2, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(2, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(2, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(2, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(2, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(2, getutcdate()) 


INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(3, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(3, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(3, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(3, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(3, getutcdate()) 
INSERT INTO [#bank] (bnk_acc_id, bnk_date) VALUES(3, getutcdate()) 


GO 
WITH [Grouped] AS (
SELECT bnk_id 
    , bnk_acc_id 
    , bnk_date 
    , ROW_NUMBER() 
    OVER (
     PARTITION BY [bnk_acc_id] 
     ORDER BY [bnk_date] DESC 
    ) [RowInGroup] 
FROM [#bank] 
) 

SELECT * FROM [Grouped] 
     WHERE [RowInGroup] <= 5 


DROP TABLE [#bank] 

Основная часть

WITH [Grouped] AS (
SELECT bnk_id 
    , bnk_acc_id 
    , bnk_date 
    , ROW_NUMBER() 
    OVER (
     PARTITION BY [bnk_acc_id] 
     ORDER BY [bnk_date] DESC 
    ) [RowInGroup] 
FROM [#bank] 
) 

SELECT * FROM [Grouped] 
     WHERE [RowInGroup] <= 5 

Это создаст ваши Groupe данных, затем процедите его соответствующим образом.

Больше инфор на разбиении на MSDN:

http://technet.microsoft.com/en-us/library/ms186734.aspx

+1

Для будущих ответов: если вопрос отмечен 'sql', то ответ должен быть * стандартным * SQL. Тег 'sql' ссылается на * язык запросов * не на конкретный продукт СУБД (а не на SQL Server). (Я имею в виду нестандартный способ цитирования идентификаторов с помощью '[..]' - Общее выражение таблицы и функции окна ** являются стандартными SQL) –

0

В зависимости от базы данных, вы можете иметь доступ к window functions. Например, в PostgreSQL, вы могли бы написать этот запрос в качестве

SELECT * 
FROM (
    SELECT *, row_number() OVER (PARTITION BY bnk_acc_id 
           ORDER BY bnk_date DESC) rn 
    FROM bank 
) AS b 
WHERE rn <= 5 
ORDER BY bnk_acc_id, bnk_date DESC 

Это работает путем присвоения номера строки для каждой строки секционированной попутным банка и упорядочены по дате, затем фильтруют до первых 5 номеров строк для каждого банка ,

Из ваших SQL-образцов, похоже, вы используете MySQL, который, к сожалению, не имеет оконных функций. В этом случае ответ Гидеона Мудрого может быть вашим лучшим выбором. Кроме того, MySQL имеет user defined variables, который может использоваться для эмуляции оконных функций, как объясняется в сообщении блога Analytic functions: FIRST_VALUE, LAST_VALUE, LEAD, LAG. Однако это может быть слишком неэффективным для ваших нужд, поскольку вы, скорее всего, окажетесь с полным сканированием таблицы.

Смежные вопросы