powered by simpleCommunicator - 2.0.52     © 2025 Programmizd 02
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Разные варианты выгрузки данных
8 сообщений из 8, страница 1 из 1
Разные варианты выгрузки данных
    #40030948
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуйте!

Есть SQL код. Даны две таблицы Shops (торговые точки) и Sales (продажи). Нужно по каждой торговой точке показать количество продаж за заданный период. Сделал в 5-и вариантах.
SQL
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
USE TestSQL_2;

DROP TABLE IF EXISTS dbo.Sales;
DROP TABLE IF EXISTS dbo.Shops;

CREATE TABLE dbo.Shops
(
	Id INT NOT NULL,
	NameShop NVARCHAR(20) NOT NULL,
	CONSTRAINT primary_shops PRIMARY KEY (Id)
);

INSERT INTO dbo.Shops
	(Id, NameShop)
VALUES
	(1, 'ТТ1'), (2, 'ТТ2'), (3, 'ТТ3'), (4, 'ТТ4');

--SELECT * FROM dbo.Shops

CREATE TABLE dbo.Sales
(
	Id INT NOT NULL,
	Date DATETIME NOT NULL,
	Sale DECIMAL(8,2),
	Id_shop INT NOT NULL,
	CONSTRAINT primary_sales PRIMARY KEY (Id),
	CONSTRAINT foreign_sales FOREIGN KEY (Id_shop) REFERENCES Shops (id)
);

INSERT INTO dbo.Sales
	(Id, Date, Sale, Id_shop)
VALUES
	(1, '01.01.2019', 100, 1), (2, '02.01.2020', 100, 1), (3, '03.03.2020', 300, 1), (4, '05.03.2020', 200, 1),
	(5, '01.01.2019', 200, 2), (6, '02.03.2020', 300, 2), (7, '03.03.2020', 300, 2), (8, '08.03.2020', 800, 2),
	(9, '01.01.2019', 100, 3), (10, '02.01.2020', 90, 3), (11, '03.03.2020', 130, 3), (12, '09.03.2020', 200, 3);

--SELECT * FROM dbo.Sales  

DECLARE
	@Month INT = 3,
	@Year INT = 2020

-- ------------------------------------------------------------------------------------------------------------------

--Вариант 1
SELECT	
	Sh.NameShop AS 'Торговая точка',	
	ISNULL(Sa.[Количество продаж], 0) AS 'Количество продаж',	
	FORMAT(Sa.[Поздняя дата], 'dd/MM/yyyy') AS 'Поздняя дата'
FROM
	dbo.Shops AS Sh
LEFT JOIN
	(SELECT
		Id_shop,
		COUNT(Sale) AS 'Количество продаж',
		MAX(Date) AS 'Поздняя дата'
	FROM
		dbo.Sales
	WHERE
		MONTH(Date) = @Month
		AND
		YEAR(Date) = @Year
	GROUP BY
		Id_shop
		) AS Sa
ON
	Sh.Id = Sa.Id_shop;

--Вариант 2
/*SELECT
	NameShop AS 'Торговая точка',
	ISNULL(Sale, 0) AS 'Количество продаж',
	FORMAT(Date, 'dd/MM/yyyy') AS 'Поздняя дата'
FROM
	(SELECT	
		Sh.NameShop,			
		COUNT(Sa.Sale) AS 'Sale',
		MAX(Sa.Date) AS 'Date'
	FROM
		dbo.Shops AS Sh
	LEFT JOIN
		dbo.Sales AS Sa
	ON
		Sh.Id = Sa.Id_shop
	WHERE
		MONTH(Sa.Date) = @Month
		AND
		YEAR(Sa.Date) = @Year
	GROUP BY
		Sh.NameShop) AS Tab;*/

--Вариант 3 (Доработанный Вариант 2)
SELECT
	NameShop AS 'Торговая точка',
	ISNULL(Sale, 0) AS 'Количество продаж',
	FORMAT(Date, 'dd/MM/yyyy') AS 'Поздняя дата'
FROM
	(SELECT	
		Sh.NameShop,			
		COUNT(CASE WHEN MONTH(Sa.Date) = @Month AND YEAR(Sa.Date) = @Year THEN 1 END) AS 'Sale',
		MAX(CASE WHEN MONTH(Sa.Date) = @Month AND YEAR(Sa.Date) = @Year THEN Sa.Date END) AS 'Date'
	FROM
		dbo.Shops AS Sh
	LEFT JOIN
		dbo.Sales AS Sa
	ON
		Sh.Id = Sa.Id_shop		
	GROUP BY
		Sh.NameShop) AS Tab;

--Вариант 4
SELECT	
	Sh.NameShop AS 'Торговая точка',		
	ISNULL(
		(SELECT COUNT(sa.Sale) AS 'Количество продаж' FROM dbo.Sales AS Sa WHERE Sh.Id = Sa.Id_shop AND MONTH(Sa.Date) = @Month AND YEAR(Sa.Date) = @Year),
			0)
		AS 'Количество продаж',
	FORMAT(
		(SELECT MAX(sa.Date) AS 'Поздняя дата' FROM dbo.Sales AS Sa WHERE Sh.Id = Sa.Id_shop AND MONTH(Sa.Date) = @Month AND YEAR(Sa.Date) = @Year ),
		'dd/MM/yyyy')
		AS 'Поздняя дата'
FROM
	dbo.Shops AS Sh;

--Вариант 5
SELECT 
	DISTINCT --!
	Sh.NameShop AS 'Торговая точка',		
	ISNULL(COUNT(Sa.Sale) OVER(PARTITION BY Sh.Id), 0) AS 'Количество продаж',
	FORMAT(MAX(Sa.Date) OVER(PARTITION BY Sh.Id), 'dd/MM/yyyy') AS 'Поздняя дата'	
FROM
	dbo.Shops AS Sh
LEFT JOIN
	dbo.Sales AS Sa
ON
	Sh.Id = Sa.Id_shop
WHERE
	MONTH(Sa.Date) = @Month
	AND
	YEAR(Sa.Date) = @Year;

РезультатыВариант 1
Торговая точка Количество продаж Поздняя датаТТ1 2 05.03.2020ТТ2 3 08.03.2020ТТ3 2 09.03.2020ТТ4 0 NULL


Вариант 2
Торговая точка Количество продаж Поздняя датаТТ1 2 05.03.2020ТТ2 3 08.03.2020ТТ3 2 09.03.2020

Вариант 3
Торговая точка Количество продаж Поздняя датаТТ1 2 05.03.2020ТТ2 3 08.03.2020ТТ3 2 09.03.2020ТТ4 0 NULL

Вариант 4
Торговая точка Количество продаж Поздняя датаТТ1 2 05.03.2020ТТ2 3 08.03.2020ТТ3 2 09.03.2020ТТ4 0 NULL

Вариант 5
Торговая точка Количество продаж Поздняя датаТТ1 2 05.03.2020ТТ2 3 08.03.2020ТТ3 2 09.03.2020Вариант 1. Работает правильно.
Вариант 2. Не отображает "ТТ4". Не смотря на LEFT это влияет на WHERE.
Вариант 3. Это доработанный вариант 2. Работает правильно. Но этот вариант будто получился не оптимальным: два раза WHERE помещен в агрегатные функции.
Вариант 4. Работает правильно.
Вариант 5. Без DISTINCT дублируются ТТ и значения. А также не отображается "ТТ4".


Вопрос 1. Возможно ли в третьем варианте написать оптимальнее (чтобы два раза не писать WHERE в агрегатных функциях)?

Вопрос 2. Я правильно понимаю, что для варианта 4 оптимальнее уже не напишешь?

Вопрос 3. Почему в 5-м варианте без DISTINCT дублируются записи и не отображается "ТТ4"?

Вопрос 4. Есть вариант, написать еще по короче?
...
Рейтинг: 0 / 0
Разные варианты выгрузки данных
    #40030954
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ferzmikk,

непонятно, вы участвуете в соревнованиях, зачем "оптимальнее"? Чем-то результат не устраивает?
...
Рейтинг: 0 / 0
Разные варианты выгрузки данных
    #40030957
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Для чего все эти издевательства над сервером?
Код: sql
1.
2.
3.
4.
5.
6.
7.
select
 a.NameShop, count(b.Id_shop), max(b.Date)
from
 dbo.Shops a left join
 dbo.Sales b on b.Id_shop = a.id and b.Date >= datefromparts(@Year, @Month, 1) and b.Date < dateadd(month, 1, datefromparts(@Year, @Month, 1))
group by
 a.Id, a.NameShop;
...
Рейтинг: 0 / 0
Разные варианты выгрузки данных
    #40030962
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Владислав Колосов
ferzmikk,

непонятно, вы участвуете в соревнованиях, зачем "оптимальнее"? Чем-то результат не устраивает?
Не участвую. Экспериментирую с разными вариантами.
...
Рейтинг: 0 / 0
Разные варианты выгрузки данных
    #40030963
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
invm
Для чего все эти издевательства над сервером?
Код: sql
1.
2.
3.
4.
5.
6.
7.
select
 a.NameShop, count(b.Id_shop), max(b.Date)
from
 dbo.Shops a left join
 dbo.Sales b on b.Id_shop = a.id and b.Date >= datefromparts(@Year, @Month, 1) and b.Date < dateadd(month, 1, datefromparts(@Year, @Month, 1))
group by
 a.Id, a.NameShop;

Интересный вариант. Спасибо!
...
Рейтинг: 0 / 0
Разные варианты выгрузки данных
    #40031027
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
invm
Для чего все эти издевательства над сервером?
Код: sql
1.
2.
3.
4.
5.
6.
7.
select
 a.NameShop, count(b.Id_shop), max(b.Date)
from
 dbo.Shops a left join
 dbo.Sales b on b.Id_shop = a.id and b.Date >= datefromparts(@Year, @Month, 1) and b.Date < dateadd(month, 1, datefromparts(@Year, @Month, 1))
group by
 a.Id, a.NameShop;


Ну а если абсолютно ненужный join из под группировки вынести - ваще взлетит.
...
Рейтинг: 0 / 0
Разные варианты выгрузки данных
    #40031036
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aleks222
Ну а если абсолютно ненужный join из под группировки вынести - ваще взлетит.
А догадайся с трех раз - зачем в группировке a.Id?
...
Рейтинг: 0 / 0
Разные варианты выгрузки данных
    #40031120
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По поводу пятого варианта. Чтобы не дублировалось - надо было добавить GROUP BY. А также чтобы отображалось "ТТ4" - надо убрать WHERE и выражение, которое было в WHERE, добавить в ON.
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
--Вариант 5
SELECT 
	Sh.NameShop AS 'Торговая точка',		
	ISNULL(COUNT(Sa.Sale) OVER(PARTITION BY Sh.Id), 0) AS 'Количество продаж'--,
	--FORMAT(MAX(Sa.Date) OVER(PARTITION BY Sh.Id), 'dd/MM/yyyy') AS 'Поздняя дата'
FROM
	dbo.Shops AS Sh
LEFT JOIN
	dbo.Sales AS Sa
ON
	Sh.Id = Sa.Id_shop
        AND
	MONTH(Sa.Date) = @Month
	AND
	YEAR(Sa.Date) = @Year
GROUP BY
	Sh.Id,
	Sh.NameShop

Но теперь возникает такая ошибка " Столбец "dbo.Sales.Sale" недопустим в списке выбора, поскольку он не содержится ни в агрегатной функции, ни в предложении GROUP BY. ".

Как поле Sa.Sale не содержится в агрегатной функции, если присутствует в COUNT? И зачем Sa.Sale присутствовать в GROUP BY, если это агрегирующее поле? Как правильно написать?
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Разные варианты выгрузки данных
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]