PHP: `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `string` varchar(255) NOT NULL, PRIMARY KEY (id), UNIQUE KEY (string) Нужно вставить значение в БД, но есть условие: Если запись `string` в БД ЕСТЬ: вернуть ID этой записи НЕТ: сделать запись и вернуть ID этой записи Кроме этого ID т.к. это AI не должен обновляться и увеличиваться, т.е. по факту ID не увеличивается, но где-то там внутри увеличение идет и при добавлении новой записи, происходит что то типа 1|string1 7|string2
Увеличение автоикрементального счетчика при попытке добавить запись – это норма. Кто такие условия придумывает? --- Добавлено --- Не давайте пользователю запустить действие при помощи предварительной проверки. Вероятность появления подобных «разрывов» существенно снизится.
Мне нужно писать в БД юзерагент пользователя и писать только уникальный юзерагент. А если у меня 100к абсолютно новых посетителей каждые сутки. Т.е. ID будет расти очень быстро. --- Добавлено --- PHP: `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `ua` varchar(255) NOT NULL, PRIMARY KEY (id), UNIQUE KEY (ua) И еще такой момент написал такой запрос: PHP: $sql = "INSERT IGNORE INTO `user_agent_insert_ignore_into` SET `ua` = 'test string3'"; но PHP: $pdo->lastInsertId() возвращается (отличным от нуля), только при добавлении уникального значения, а нужно чтоб возвращался и при совпадении (т.е. если существует, возвращать ID существующего) Будут и другие данные которые хотелось бы точно также записывать. Ибо зачем писать в БД однотипные записи но с разным ID
Я так понял что мою хотелку можно решить через создание функции, написал функцию, но вот не работает: PHP: CREATE FUNCTION get_id_data(data VARCHAR(255), tablename VARCHAR(255), colname VARCHAR(255)) RETURNS INT BEGIN DECLARE tablename, colname, count INT; SELECT COUNT(colname) INTO count FROM tablename; IF count = 0 THEN INSERT INTO tablename(colname) VALUES (data); SELECT LAST_INSERT_ID() INTO count; END IF; RETURN count; END Т.е. идея была такова, чтоб функция была универсальна и работала под разные схожие таблицы и поэтому было решено передавать через аргументы имя функции и имя столбца, но появляется ошибка что в базе данных не существет таблицы с конкретно именем tablename. Т.е. через аргумент просто не передается имя таблицы, чтобы я ни передавал, все время пишет, что tablename не существует.
@AlexandrS, не надо нихера выдумывать, всё уже давно придумано, достаточно прочесть пару тройку книг. Если после прочтения и дальше будешь городить эту чушь называя каким-то универсальным решением, то бросай программирование это не твоё.
Твои слова, это слова недалекого человека который тешит свое ЧСВ! Не более! У тебя даже мозгов не хватает увидеть разницу между прочесть и изучить (книгу и материал изложенный в ней), а ты тут еще пытаешься умничать. О каких книгах ты вообще говоришь? Ты бы хотя бы название написал. Так что ты очередной пустозвон разбрасывающийся словесными высерами.
Похоже ты очередной ушлепок, который вместо того чтоб подсказать, где человек ошибается, язвит. Таких умных из себя сроете, а по факту ущербные ЧСВшники.
@AlexandrS, ты такой ранимый. Это самозащита называется в психологии "проекция". Твои тексты больше говорят о тебе. И почему ты решил, что это шутка, уже не интересно знать. Удачи в борьбе со всеми
Решение сделал такое: PHP: DELIMITER // CREATE FUNCTION get_id_data(data VARCHAR(255)) RETURNS INT BEGIN DECLARE count INT; SELECT id INTO count FROM user_agent_insert_into WHERE ua = data; IF count IS NULL THEN BEGIN INSERT INTO user_agent_insert_into(ua) VALUES (data); SELECT LAST_INSERT_ID() INTO count; END; END IF; RETURN count; END // Если два умника язвивших выше, имеют свое решение данного вопроса, хотелось бы увидеть.
В MySQL есть insert ... on duplicate key update, а так, можно было в два запроса решить, без функции внутри mysql
Я вначале думал сделать на PHP так: Селект, если пусто тогда Инсерт. Т.е. по сути то что организованно в функции для MySQL С insert ... on duplicate key update я так и не нашел решения, т.к. ID увеличивался, т.е. к примеру последний ID был 5, затем пришло 100 одинаковых запросов, выполнился insert ... on duplicate key update, сам ID не менялся, но вот когда прилетел уникальный запрос, тогда ID стал 105, а мне нужно чтоб он был 6. Вот в чем загвоздка. А делать проверку через ПХП как написал вначале (Селект, если пусто тогда Инсерт.), то я решил что это будет не камельфо, гонять туда сюда.
@mkramer, подтверждаю написанное выше: от инкремента при апдэйте эта конструкция не спасет. --- Добавлено --- Что гонять? Выбирайте мин. данных. Только это не атомарно, как и использование хранимой ф-ции. Я пока не вижу какой-то практической пользы во всей этой затее, поэтому и оптимальное решение предложить не могу.
Польза в том чтоб не создавать десятки тысяч одинаковых записей ЮзерАгентов, а наличие ЮА мне необходимо, поэтому я пришел к тому, что проще к каждому уникальному ЮА прикрепить ID и держать только уникальные ЮА, и уже дальше с этим ID работать. К примеру пришел одна таблица: ID | UserName | UserAgent 1 | Вася | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 2 | Петя | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 3 | Коля | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 4 | Толя | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 У всех одинаковый UA зачем забивать таблицу одним и тем же? Не проще ли сделать 2 таблицы ID | UserName | UserAgentID 1 | Вася | 1 2 | Петя | 1 3 | Коля |1 4 | Толя | 1 UserAgentID | UserAgent 1 | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 Я так понимаю это и есть нормализация БД или я что-то не правильно уловил? ----- А касаемо "Гонять". Я просто подумал, что по сути проще было собрать всё в одно целое в MySQL и из ПХП делать одно обращение к MySQL и получить результат. А так вначале, как я уже писал, нужно делать запрос через SELECT, если ID пришел то двигаемся дальше, если нет , то нужно сделать INSERT и получить LAST_INSERT_ID. В этом конечно есть своя прелесть, например в том, что можно написать один раз функции и если подобных таблиц несколько, то просто в аргументах передавать имя таблицы и столбца и получать результат, это можно тоже сделать и на MySQL, но это не камельфо. Короче говоря, тут пока на практике не начнешь что-то применять, размышлять можно долго. В любом случае в решении этой задачи я получил какие-то полезные знания.
Для решения подобного рода задачи применяют буферные таблицы для вставки "сырых данных" которые не имеют индексов кроме первичного, еще лучше если таблица расположена в оперативной памяти, еще лучше если это NoSQL база данных типа Redis. Создаётся таблица с названием текущей даты и данные записываются сплошным потоком, меняется дата данные записываются в другую таблицу, а "вчерашнюю" таблицу можно спокойно обрабатывать и раскладывать данные в таблицы MySQL как душе угодно, для последующего анализа. Если для анализа требуется актуальная информация это тоже решаемо. @AlexandrS, а теперь о главном, ты даже не плюнул, ты нассал в колодец, а посему в рамках повышения своего и без того непомерного ЧСВ добавлю ка тебя в игнор. Будет очень больно не видеть твоих новоиспечённых тем и комментариев, но я сильный, я справлюсь.
1. Логи можно не нормализовывать. Или использовать отложенную нормализацию. 2. Нашел в закромах оч. похожее, но с частично отложенной нормализацией (там в том числе используется и промежуточная денормализованная таблица, о кот. Валик писал), поэтому выкладываю компиляцию, сделанную на коленке (псевдокод): Код (Text): if (ISNULL(SELECT `uid` FROM `dictionary_table` WHERE `unique`=$unique)): INSERT IGNORE INTO `dictionary_table` (`unique`) VALUES ($unique); INSERT INTO `table` (`uid`) VALUES (IFNULL((SELECT `uid` FROM `dictionary_table` WHERE `unique`=$unique),0)) else: INSERT INTO `table` (`uid`) VALUES ($uid) Возможно, вместо IFNULL() можно использовать [SELECT] LAST_INSERT_ID(), но запись с нулевым id по-любому нужно иметь в словаре. 3. В слове «камельфо» насчитал две ошибки
Есть еще такой вариант: PHP: INSERT INTO `user_agent_insert_into` (ua) SELECT 'test_7' FROM DUAL WHERE NOT EXISTS ( SELECT `id` FROM `user_agent_insert_into` WHERE `ua` = 'test_7' ); Но тут проблема в том, что не возвращается результат SELECT. Если вставка произошла, вернется last_id, а вот если запись существует ID этой записи не возвращается.