powered by simpleCommunicator - 2.0.56     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Хитрая выборка из двух таблиц
23 сообщений из 23, страница 1 из 1
Хитрая выборка из двух таблиц
    #32131075
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Опять я вас достаю своими проблемами - но прошу извинить - больше обратится некуда, а я в TSQL хреново понимаю...
Есть две таблицы:

tovar - таблица характеристик товаров
================
Kod - уникальный код товара
Name - название товара
================

zena - таблица с историями цен товаров
================
Kod - код товара
Data - дата установки цены на товар
Price - значение цены на дату
================

Как можно сделать выборку, что бы в нее попали название товаров и цены этих товаров на определенную дату?
Типа такая должна быть картина:

+=========================+=======+
| Товар | Цена |
+=========================+=======+
Телевизор Sony E-25 7000
Чайник Скарлет-1022 800
Утюг PHILIPS-78 950
==================================
Можно-ли это сделать опять-таки одним запросом, без временных таблиц?
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131086
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
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.
CREATE DATABASE sex;
USE sex;

CREATE TABLE tovar (
  Kod CHAR( 4 ),
  Name VARCHAR( 50 )
);

CREATE TABLE Zena (
  Kod CHAR( 4 ),
  Data DATE,
  Price SMALLINT( 5 ) UNSIGNED
);

INSERT INTO tovar VALUES ('1077', 'Чайник Скарлет-1022');
INSERT INTO tovar VALUES ('5618', 'Утюг PHILIPS-78');
INSERT INTO tovar VALUES ('3388', 'Телевизор Sony E-25');

INSERT INTO Zena VALUES ('5618', '2002-12-30',  900 );
INSERT INTO Zena VALUES ('5618', '2003-01-25',  920 );
INSERT INTO Zena VALUES ('5618', '2003-03-02',  950 );

INSERT INTO Zena VALUES ('1077', '2002-12-30',  750 );
INSERT INTO Zena VALUES ('1077', '2003-02-18',  800 );

INSERT INTO Zena VALUES ('3388', '2002-12-30',  6580 );
INSERT INTO Zena VALUES ('3388', '2003-01-15',  7200 );
INSERT INTO Zena VALUES ('3388', '2003-03-02',  7000 );
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131136
Артем1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
declare @d DATETIME
set @d = '20030125'

select t.*, 
      (select top  1  Price 
       from zena 
       where 
         (Kod = t.Kod) 
          and 
         (  DateDiff(day, Data, @d) = (select min( DateDiff(day, Data, @d) ) from zena where zena.kod = t.kod ) ) ) 
from tovar t


Как то так должно работать. По крайне мере результат сходится.
Писал на Transact-SQL (у меня SQL Server), так что адаптируеш сам.
Сорри за корявое оформление.
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131174
Фотография mahoune
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Он бы адаптировал. Только навряд ли у него есть вложенные запросы в MySQL!

2BigHarry, у делали-же с этой базой уже что-то тут?!
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131225
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да - это для МуСкуля...
Тама вложенных запросов (в трешке) точно нету.
Четверка - ещо сырая, что бы ее ставить...
(2) mahoune - да - делали, но там была другая проблема - и она не без вашей помощи разрешилась...
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131339
medved
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Короче говоря....
1. если тебе нужен запрос, который тебе выдает - у каких товаров были изменения по цене за данную дату, то никаких проблем:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
select
		tovar.Name,
		zena.Price,
		 "2002 - 12 - 31 " as Data
from 
		zena,
		tovar
where 
		tovar.Kod = zena.Kod
	and
		Data =  "2002 - 12 - 30 "
group by tovar.Kod;

Соотвествно, он не выведет тебе товары, у которых не было изменения цены за данное число.

2. если тебе нужен запрос, который тебе выдает - были ли изменения по цене у товаров за данную дату, то тоже никаких проблем:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
select
		tovar.Name,
		if(ISNULL(zena.Price),  "Нет изменений" , zena.Price) as Price,
		 "2002 - 12 - 31 " as Data
from 
		tovar
left join
		zena
	on
			tovar.Kod = zena.Kod
		and
			Data =  "2002 - 12 - 31 ";


3. если тебе нужен запрос, который выберет ближайшее изменение к этой дате, то лично у меня возникли проблемы, которые я решил таким способом:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
select
		tovar.Name,
		min(CONCAT(ABS(to_days(zena.Data)-to_days( "2003 - 02 - 03 ")),  "0101010101 ", zena.Price)) as _diff,
		Data
from 
		zena,
		tovar
where 
		tovar.Kod = zena.Kod
group by tovar.Kod;


только придется выделять на стороне клиента цену из поля diff (разделитель, в моем случае, 0101010101. он должен быть числовым).

4. Если чего то еще, то пиши

Удачи.
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131341
medved
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
P.S. Четверка, то вроде уже не сырая, покрайней версия 4.012 (источник новость на MySQL.com) рекомендованна к использованию.... Вот только вложенных запросов в ней попрежнему нету. :(

P.S. Последний пример: мона разбивать и в Мускуле (чего то мысля дальше не пошла :( ), и такой пример описываеться в доке на все том же MySQL.com
http://www.mysql.com/doc/ru/example-Maximum-column-group-row.html и назван не эффективным... :(. Ну это я и сам знал.
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131356
medved
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
P.P.P.S чего-то Артем разошелся.... Два вложенных запроса.... Ни есть гуд.
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131665
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
(2) medved
Что-то не получается...
Мне нужна возможность получать цену по товарам на определенную дату (дата задается юзером).
Я попробовал твой третий вариант, но почему-то он выдает неправильный результат:
Имеется такая запись в таблице Zena
Код: plaintext
1.
2.
3.
INSERT INTO Zena VALUES ('5730', '2002-12-31',  11290 );
INSERT INTO Zena VALUES ('5730', '2003-01-06',  11790 );
INSERT INTO Zena VALUES ('5730', '2003-02-05',  12190 );


Что бы узнать цену на дату 03-02-2003 (цена должна быть 11790) запрос:
select tovar.Name, min(CONCAT(ABS(to_days(zena.Data)- to_days("2003-02-03")), "0101010101", zena.Price)) as _diff, Data from zena, tovar
where tovar.kod='5730' AND (tovar.Kod = zena.Kod) group by tovar.Kod;
возвращает значение 12190, а такое значение цены должно быть позжее.
Может - как-то извратиться с временной выборкой?
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131705
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Странно, но правильный результат выдает следующий запрос (искомая дата - 01.02.2003):
Код: plaintext
1.
2.
3.
SELECT tovar.Name, zena.Price
FROM tovar,zena 
WHERE zena.Data <=  "2003 - 02 - 01 " AND (zena.Kod = tovar.Kod)
GROUP by tovar.Kod
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131800
medved
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Моя таблица zena

Kod  Data  Price
5618  2002-12-30  900  
5618  2003-01-25  920  
5618  2003-03-02  950  
1077  2002-12-30  750  
1077  2003-02-18  800  
3388  2002-12-30  6580  
3388  2003-01-15  7200  
3388  2003-03-02  7000  
5730  2002-12-31  11290  
5730  2003-01-06  11790  
5730  2003-02-05  12190  

Твой запрос
Код: plaintext
1.
2.
3.
SELECT tovar.Kod, tovar.Name, zena.Price
FROM tovar,zena 
WHERE zena.Data <=  "2003 - 02 - 01 " AND (zena.Kod = tovar.Kod)
GROUP by tovar.Kod


результат твоего запроса

Kod  Name  Price
1077  Чайник Скарлет-1022  750  
3388  Телевизор Sony E-25  6580  
5618  Утюг PHILIPS-78  900  

Для товара с кодом 5618 цена ближайшая по дате к к дате "2003-02-01",
"920" за дату 2003-01-25. Твой запрос выводит не эту, он выводит первую запись с датой меньше чем ты задал

Мой запрос
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
select
		tovar.Name,
		min(CONCAT(ABS(to_days(zena.Data)-to_days( "2003 - 02 - 01 ")),  "0101010101 ", zena.Price)) as _diff
from 
		zena,
		tovar
where 
		tovar.Kod = zena.Kod
group by tovar.Kod;


результат моего запроса

Name    _diff
Чайник Скарлет-1022    170101010101 800   
Телевизор Sony E-25    17010101010 17200   
Утюг PHILIPS-78    290101010101 950   

Проверяем:

Код товара 3388 ближайшая по дате цена 7200 за 2003-01-15
Код товара 5618 ближайшая по дате цена 920 за 2003-01-25
Код товара 1077 ближайшая по дате цена 800 за 2003-02-18

Я поставил там abs для того что бы считало как и после заданой даты так и до... Если тебе надо ближайшая цена с датой меньше заданной надо

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
select
		tovar.Name,
		min(CONCAT(ABS(to_days(zena.Data)-to_days( "2003 - 02 - 01 ")),  "0101010101 ", zena.Price)) as _diff
from 
		tovar
left join
		zena
	on
			tovar.Kod = zena.Kod
		and
			zena.Data< "2003 - 02 - 01 "
group by tovar.Kod
order by tovar.Kod


А мой запрос у меня лично не работает потому что у меня нет товара с кодом
5730... Как только я его добавил все появилось.
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131805
medved
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
"А мой запрос у меня лично не работает потому что у меня нет товара с кодом
5730... Как только я его добавил все появилось." - я хотел сказать что вот этот запрос не работает:

select tovar.Name, min(CONCAT(ABS(to_days(zena.Data)- to_days("2003-02-03")), "0101010101", zena.Price)) as _diff, Data from zena, tovar
where tovar.kod='5730' AND (tovar.Kod = zena.Kod) group by tovar.Kod;
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131846
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да - мой запрос лажает...
Твой, который последний - похоже то, что нужно, вот только столбец, который он возвращает - какой-то некузявный - из него ещо надо каким-то макаром вычипить цену...
Пойду гляну в ману - надо же хоть до чего-то самому допереть...
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131864
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сделал так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
SELECT tovar.Name,
MIN(CONCAT(ABS(to_days(zena.Data)-to_days( "2003 - 02 - 01 ")),  "0101010101 #", zena.Price)) as _diff
FROM tovar
LEFT JOIN zena ON tovar.Kod = zena.Kod AND zena.Data< "2003 - 02 - 01 "
group by tovar.Kod
HAVING _diff != ""
ORDER BY tovar.Name

Вроде - все нормально - теперь цену можно отделить по поиску подстроки #
Блин, хочется что бы цену в нормальном виде не на клиенте обрабатывать, а получать в виде числа с сервера, иначе - тормозит...

А каким запросом можно скинуть цены на определенную дату во временную таблицу (при условии что дата цены меньше или равна требуемой даты)?
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131866
medved
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну если пхп
то где-нидь так:
Код: plaintext
1.
2.
list($data_diff, $price) = explode( "0101010101 ", $db->result($result,  0 , '_diff'));
echo $price;
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131881
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не - не для пхп, надо как столбец в Дельфи, и тама должно быть число...
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32131951
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нифига не получаеться!
Помогите, плиз, как мне сделать выборку в другую таблицу, типа так:
Код: plaintext
1.
2.
3.
4.
SELECT INTO temptable UNIQUE(zena.Kod), zena.Data, zena.Price
FROM zena 
WHERE zena.Data <=  "2003 - 02 - 01 "
ORDER BY Kod, Data DESC
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32132190
medved
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
select
		tovar.Name,
		SUBSTRING(
							min(CONCAT(ABS(to_days(zena.Data)-to_days( "2003 - 02 - 01 ")),  "12345678987654321 ", zena.Price)), 
							 17 +LOCATE(
												 "12345678987654321 ", 
												min(
														CONCAT(
																		ABS(to_days(zena.Data)-to_days( "2003 - 02 - 01 ")), 
																		 "12345678987654321 ", 
																		zena.Price)
													)
									)
		) as _diff
from 
		tovar
left join
		zena
	on
			tovar.Kod = zena.Kod
		and
			zena.Data< "2003 - 02 - 01 "
group by tovar.Kod
order by tovar.Kod


Ну теперь в поле _price цена товара
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32132718
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я уже выкрутился, через темповую таблу. Хотел сначала через строковые функции, как ты и предложил, но выражение получалось запарно-длинное - я подумал, что Мускуль быстрее с темповой таблой прокрутится...
Вот что получилось:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
CREATE TEMPORARY TABLE pricetmp (Kod CHAR( 4 ) NOT NULL,
Price SMALLINT( 5 ) UNSIGNED NOT NULL,
FakeNum SMALLINT( 3 ) UNSIGNED NOT NULL,
PRIMARY KEY (Kod));

INSERT INTO pricetmp SELECT zena.Kod, zena.Price,
MIN(to_days(NOW())-to_days(zena.Data)) AS sex
FROM zena
WHERE zena.Data <= NOW()
GROUP BY Kod;

SELECT tovar.Name,
IFNULL(pricetmp.Price, 0 ) AS Price
FROM tovar
LEFT JOIN pricetmp ON pricetmp.Kod=tovar.Kod
WHERE tovar.Folder='0'
GROUP BY tovar.Kod;
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32133874
Chira
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Один SQL:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
select t.*,z1.kod,max(z1.data),z2.data,z2.price
from zena z1, zena z2, tovar t
where z1.kod = z2.kod and z1.data <= '2003-02-03' and z2.data <= '2003-02-03'
	and t.kod = z1.kod
group by z1.kod,z2.data, z2.price
having z2.data = MAX(z1.data)
;

через TEMP таблицу будет быстрее
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
CREATE TEMPORARY TABLE pricetmp
TYPE=HEAP
SELECT Kod, MAX(Data)
FROM zena
WHERE Data <= NOW()
GROUP BY Kod;

SELECT tovar.Name,
IFNULL(zena.Price, 0 ) AS Price
FROM tovar
LEFT JOIN pricetmp ON pricetmp.Kod=tovar.Kod
LEFT JOIN zena ON pricetmp.Kod=zena.Kod AND pricetmp.data=zena.data
WHERE tovar.Folder='0'
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32133913
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Проверил - первый запрос вааще ничего не возвращает - ошибки нет, но и выборка пуста, а второй - почти такой-же, как и у меня, только - у меня ещо индекс построен по коду в темповой таблице, иначе LEFT JOIN минуты две-три выстраивается, и при этом ресурсы мускуль начинает отжирать...
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32133938
Chira
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
первый запрос для приведенных здесь данных на дату 2003-02-03
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
+ ------+---------------------+------+--------------+------------+-------+
 
| Kod  | Name                | kod  | max(z1.data) | data       | price |
+ ------+---------------------+------+--------------+------------+-------+
 
|  1077  | Чайник Скарлет- 1022  |  1077  |  2002 - 12 - 30    |  2002 - 12 - 30  |    750  |
|  3388  | Телевизор Sony E- 25  |  3388  |  2003 - 01 - 15    |  2003 - 01 - 15  |   7200  |
|  5618  | Утюг PHILIPS- 78      |  5618  |  2003 - 01 - 25    |  2003 - 01 - 25  |    920  |
+------+---------------------+------+--------------+------------+-------+

Насчет второго варианта - временная таблица создается как HEAP (в памяти), следовательно индексы для нее не нужны.
Если у тебя большой объем данных (в память не влезет), то нужно пересмотреть конструкцию.
...
Рейтинг: 0 / 0
Хитрая выборка из двух таблиц
    #32210741
BigHarry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем - обломился - мой вариант не дает правильных данных.
Что бы эта ветка никого не ввела в заблуждение и кто-то не напоролся на грабли, вот правильный запрос:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
CREATE TEMPORARY TABLE pricetmp (Kod CHAR( 4 ) NOT NULL,
Price SMALLINT( 5 ) UNSIGNED NOT NULL,
PRIMARY KEY (Kod));

INSERT INTO pricetmp SELECT Kod, Price
FROM zena WHERE Data <= NOW()
ORDER BY Kod, Data DESC;


В данном случае в темпоральную таблицу будут вставляться данные в порядке возрастания дат, а поскольку код является примари - то вставить более чем одной записи с кодом мускуль не даст.
...
Рейтинг: 0 / 0
23 сообщений из 23, страница 1 из 1
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Хитрая выборка из двух таблиц
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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