За последние 24 часа нас посетили 20378 программистов и 1089 роботов. Сейчас ищут 826 программистов ...

Вставка значение в БД и возврат lastID

Тема в разделе "PHP и базы данных", создана пользователем AlexandrS, 23 май 2019.

  1. AlexandrS

    AlexandrS Активный пользователь

    С нами с:
    30 сен 2017
    Сообщения:
    659
    Симпатии:
    103
    Адрес:
    Краснодар
    PHP:
    1. `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    2. `string` varchar(255) NOT NULL,
    3. PRIMARY KEY (id),
    4. UNIQUE KEY (string)
    Нужно вставить значение в БД, но есть условие:

    Если запись `string` в БД
    ЕСТЬ: вернуть ID этой записи
    НЕТ: сделать запись и вернуть ID этой записи

    Кроме этого ID т.к. это AI не должен обновляться и увеличиваться, т.е. по факту ID не увеличивается, но где-то там внутри увеличение идет и при добавлении новой записи, происходит что то типа
    1|string1
    7|string2
     
  2. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.789
    Симпатии:
    646
    Увеличение автоикрементального счетчика при попытке добавить запись – это норма. Кто такие условия придумывает?
    --- Добавлено ---
    Не давайте пользователю запустить действие при помощи предварительной проверки. Вероятность появления подобных «разрывов» существенно снизится.
     
  3. AlexandrS

    AlexandrS Активный пользователь

    С нами с:
    30 сен 2017
    Сообщения:
    659
    Симпатии:
    103
    Адрес:
    Краснодар
    Мне нужно писать в БД юзерагент пользователя и писать только уникальный юзерагент. А если у меня 100к абсолютно новых посетителей каждые сутки. Т.е. ID будет расти очень быстро.
    --- Добавлено ---
    PHP:
    1. `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    2. `ua` varchar(255) NOT NULL,
    3. PRIMARY KEY (id),
    4. UNIQUE KEY (ua)

    И еще такой момент написал такой запрос:
    PHP:
    1. $sql = "INSERT IGNORE INTO `user_agent_insert_ignore_into` SET `ua` = 'test string3'";
    но
    PHP:
    1. $pdo->lastInsertId()
    возвращается (отличным от нуля), только при добавлении уникального значения, а нужно чтоб возвращался и при совпадении (т.е. если существует, возвращать ID существующего)

    Будут и другие данные которые хотелось бы точно также записывать. Ибо зачем писать в БД однотипные записи но с разным ID
     
    #3 AlexandrS, 23 май 2019
    Последнее редактирование: 23 май 2019
  4. AlexandrS

    AlexandrS Активный пользователь

    С нами с:
    30 сен 2017
    Сообщения:
    659
    Симпатии:
    103
    Адрес:
    Краснодар
    Я так понял что мою хотелку можно решить через создание функции, написал функцию, но вот не работает:

    PHP:
    1. CREATE FUNCTION get_id_data(data VARCHAR(255), tablename VARCHAR(255), colname VARCHAR(255))
    2. RETURNS INT
    3. BEGIN
    4.     DECLARE tablename, colname, count INT;
    5.     SELECT COUNT(colname) INTO count FROM tablename;
    6.     IF count = 0 THEN
    7.         INSERT INTO tablename(colname) VALUES (data);
    8.         SELECT LAST_INSERT_ID() INTO count;
    9.     END IF;
    10. RETURN count;
    Т.е. идея была такова, чтоб функция была универсальна и работала под разные схожие таблицы и поэтому было решено передавать через аргументы имя функции и имя столбца, но появляется ошибка что в базе данных не существет таблицы с конкретно именем tablename.
    Т.е. через аргумент просто не передается имя таблицы, чтобы я ни передавал, все время пишет, что tablename не существует.
     
  5. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    @AlexandrS, не надо нихера выдумывать, всё уже давно придумано, достаточно прочесть пару тройку книг. Если после прочтения и дальше будешь городить эту чушь называя каким-то универсальным решением, то бросай программирование это не твоё.
     
  6. AlexandrS

    AlexandrS Активный пользователь

    С нами с:
    30 сен 2017
    Сообщения:
    659
    Симпатии:
    103
    Адрес:
    Краснодар
    Твои слова, это слова недалекого человека который тешит свое ЧСВ! Не более!
    У тебя даже мозгов не хватает увидеть разницу между прочесть и изучить (книгу и материал изложенный в ней), а ты тут еще пытаешься умничать. О каких книгах ты вообще говоришь? Ты бы хотя бы название написал.
    Так что ты очередной пустозвон разбрасывающийся словесными высерами.
     
    #6 AlexandrS, 25 май 2019
    Последнее редактирование: 25 май 2019
  7. Vanchot

    Vanchot Активный пользователь

    С нами с:
    23 мар 2019
    Сообщения:
    104
    Симпатии:
    19
    Адрес:
    Ахерон (LV-426)
    @AlexandrS, в транзакцию ещё всё заверни.
     
  8. AlexandrS

    AlexandrS Активный пользователь

    С нами с:
    30 сен 2017
    Сообщения:
    659
    Симпатии:
    103
    Адрес:
    Краснодар
    Похоже ты очередной ушлепок, который вместо того чтоб подсказать, где человек ошибается, язвит. Таких умных из себя сроете, а по факту ущербные ЧСВшники.
     
  9. Vanchot

    Vanchot Активный пользователь

    С нами с:
    23 мар 2019
    Сообщения:
    104
    Симпатии:
    19
    Адрес:
    Ахерон (LV-426)
    @AlexandrS, ты такой ранимый. Это самозащита называется в психологии "проекция". Твои тексты больше говорят о тебе.
    И почему ты решил, что это шутка, уже не интересно знать. Удачи в борьбе со всеми :)
     
  10. AlexandrS

    AlexandrS Активный пользователь

    С нами с:
    30 сен 2017
    Сообщения:
    659
    Симпатии:
    103
    Адрес:
    Краснодар
    Решение сделал такое:
    PHP:
    1. DELIMITER //
    2. CREATE FUNCTION get_id_data(data VARCHAR(255))
    3. RETURNS INT
    4. BEGIN
    5.     DECLARE count INT;
    6.     SELECT id INTO count FROM user_agent_insert_into WHERE ua = data;
    7.     IF count IS NULL THEN
    8.         BEGIN
    9.             INSERT INTO user_agent_insert_into(ua) VALUES (data);
    10.             SELECT LAST_INSERT_ID() INTO count;
    11.         END;
    12.     END IF;
    13. RETURN count;
    14. END //
    Если два умника язвивших выше, имеют свое решение данного вопроса, хотелось бы увидеть.
     
  11. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.548
    Симпатии:
    1.754
    В MySQL есть insert ... on duplicate key update, а так, можно было в два запроса решить, без функции внутри mysql
     
  12. AlexandrS

    AlexandrS Активный пользователь

    С нами с:
    30 сен 2017
    Сообщения:
    659
    Симпатии:
    103
    Адрес:
    Краснодар
    Я вначале думал сделать на PHP так: Селект, если пусто тогда Инсерт. Т.е. по сути то что организованно в функции для MySQL
    С insert ... on duplicate key update я так и не нашел решения, т.к. ID увеличивался, т.е. к примеру последний ID был 5, затем пришло 100 одинаковых запросов, выполнился insert ... on duplicate key update, сам ID не менялся, но вот когда прилетел уникальный запрос, тогда ID стал 105, а мне нужно чтоб он был 6.
    Вот в чем загвоздка.
    А делать проверку через ПХП как написал вначале (Селект, если пусто тогда Инсерт.), то я решил что это будет не камельфо, гонять туда сюда.
     
  13. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.789
    Симпатии:
    646
    @mkramer, подтверждаю написанное выше: от инкремента при апдэйте эта конструкция не спасет.
    --- Добавлено ---
    Что гонять? Выбирайте мин. данных. Только это не атомарно, как и использование хранимой ф-ции.

    Я пока не вижу какой-то практической пользы во всей этой затее, поэтому и оптимальное решение предложить не могу.
     
  14. AlexandrS

    AlexandrS Активный пользователь

    С нами с:
    30 сен 2017
    Сообщения:
    659
    Симпатии:
    103
    Адрес:
    Краснодар
    Польза в том чтоб не создавать десятки тысяч одинаковых записей ЮзерАгентов, а наличие ЮА мне необходимо, поэтому я пришел к тому, что проще к каждому уникальному ЮА прикрепить 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, но это не камельфо.

    Короче говоря, тут пока на практике не начнешь что-то применять, размышлять можно долго. В любом случае в решении этой задачи я получил какие-то полезные знания.
     
    #14 AlexandrS, 25 май 2019
    Последнее редактирование: 25 май 2019
  15. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    Для решения подобного рода задачи применяют буферные таблицы для вставки "сырых данных" которые не имеют индексов кроме первичного, еще лучше если таблица расположена в оперативной памяти, еще лучше если это NoSQL база данных типа Redis. Создаётся таблица с названием текущей даты и данные записываются сплошным потоком, меняется дата данные записываются в другую таблицу, а "вчерашнюю" таблицу можно спокойно обрабатывать и раскладывать данные в таблицы MySQL как душе угодно, для последующего анализа. Если для анализа требуется актуальная информация это тоже решаемо.
    @AlexandrS, а теперь о главном, ты даже не плюнул, ты нассал в колодец, а посему в рамках повышения своего и без того непомерного ЧСВ добавлю ка тебя в игнор. Будет очень больно не видеть твоих новоиспечённых тем и комментариев, но я сильный, я справлюсь.
     
  16. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.789
    Симпатии:
    646
    1. Логи можно не нормализовывать. Или использовать отложенную нормализацию.

    2. Нашел в закромах оч. похожее, но с частично отложенной нормализацией (там в том числе используется и промежуточная денормализованная таблица, о кот. Валик писал), поэтому выкладываю компиляцию, сделанную на коленке (псевдокод):
    Код (Text):
    1. if (ISNULL(SELECT `uid` FROM `dictionary_table` WHERE `unique`=$unique)):
    2.   INSERT IGNORE INTO `dictionary_table` (`unique`) VALUES ($unique);
    3.   INSERT INTO `table` (`uid`) VALUES (IFNULL((SELECT `uid` FROM `dictionary_table` WHERE `unique`=$unique),0))
    4. else:
    5.   INSERT INTO `table` (`uid`) VALUES ($uid)
    Возможно, вместо IFNULL() можно использовать [SELECT] LAST_INSERT_ID(), но запись с нулевым id по-любому нужно иметь в словаре.

    3. В слове «камельфо» насчитал две ошибки :)
     
    #16 miketomlin, 25 май 2019
    Последнее редактирование: 25 май 2019
    AlexandrS нравится это.
  17. AlexandrS

    AlexandrS Активный пользователь

    С нами с:
    30 сен 2017
    Сообщения:
    659
    Симпатии:
    103
    Адрес:
    Краснодар
    ДА! Есть такое :rolleyes:, оправданий нет :)
     
  18. AlexandrS

    AlexandrS Активный пользователь

    С нами с:
    30 сен 2017
    Сообщения:
    659
    Симпатии:
    103
    Адрес:
    Краснодар
    Есть еще такой вариант:

    PHP:
    1. INSERT INTO `user_agent_insert_into` (ua)
    2. SELECT 'test_7' FROM DUAL
    3. WHERE NOT EXISTS (
    4.     SELECT `id` FROM `user_agent_insert_into`
    5.     WHERE `ua` = 'test_7'
    6. );
    Но тут проблема в том, что не возвращается результат SELECT.
    Если вставка произошла, вернется last_id, а вот если запись существует ID этой записи не возвращается.