Задать вопрос
  • Считается ли рекламой бартерный / “дружеский” пост о мероприятии (бесплатное и платное участие) в Telegram-канале, и обязательно ли заключать договор?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    Будем делать дружеские посты в тг без коммерческой основы (либо жест доброй воли автора либо обмен постами / пост взамен на гарантированную проходку или выступление в кач спикера)

    Наличие ссылки на сайт / форму регистрации (у нас с UTM-метками)

    Понятие рекламы
    Реклама - информация, распространенная любым способом, в любой форме и с использованием любых средств, адресованная неопределенному кругу лиц и направленная на привлечение внимания к объекту рекламирования, формирование или поддержание интереса к нему и его продвижение на рынке.
    Вопрос: будет ли это считаться рекламой

    Будет.
    Так как сеять будем оч много где, если со всеми заключать договоры, то 1) уйдет куча времени 2) будут меньше соглашаться на публикации из-за бюрократической возни

    Проблемы индейцев шерифа не волнуют.
    Если не ошибаюсь, когда я заносила данные в ОРД, нужно было номер договора указывать, тогда нужно ли рассматривать что-то типо:
    Договор безвозмездного оказания услуг
    Договор о взаимном информационном сотрудничестве
    Договор мены (бартера) ?

    Лучше оформить договор как встречное оказания услуг. Если планируется множественное взаимодействие с контрагентом, то можно составить базовый договор с пролонгацией, а все взаимодействия описывать в допниках к нему.
    Ответ написан
    Комментировать
  • Как обработать новое значение в свитч?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    Я не совсем понял общий смысл вашей конструкции, поэтому для наглядности, реализовал это в форме перечисления + тип + функция:
    const Names = {
      Bob: 'bob',
      Alice: 'alice',
      // Mike: 'mike',
    } as const;
    
    type Name = typeof Names[keyof typeof Names];
    
    function fn(name: Name): boolean {
      let access: boolean;
    
      switch (name) {
    
        case Names.Bob:
          access = true;
          break;
    
        case Names.Alice:
          access = false;
          break;
    
        default:
          const check: never = name;
          throw new Error(`Ошибка, пришло ${ check }`);
      }
    
      return access;
    }
    
    console.log(fn(Names.Bob)); // true

    Если в names добавить еще одно значение, например mike, и не обработать его в switch, то check сразу засветиться красным с ошибкой:
    TS2322: Type 'mike' is not assignable to type never
    Ответ написан
    2 комментария
  • Кто отвечает за ноут с ОС, которой в оригинале нет?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    Понятное дело, что за наклейку скажут "мы ничего не клеили, это вы сами", но бухгалтерских доках все указано.

    На наклейки товарищу плевать. Если товарищ подойдет формально, то спросит накладную с чеком, где перечислены приобретенные лицухи, пересчитает цыплят windows-системники, ну и на выходе цифры должны сойтись. Если не формально, то заглянет еще в настройки каждого компа, номер лицухи на компе должен быть равен номеру лицухи из накладной (один к одному).
    Есть ноут, у которого в спецификациях стоит noOS и лейбы на корпусе соответственно нет

    через магазин на юр.лицо, со всеми документами (УПД, накладные и т.д.) в которых в характеристиках добавлена система Win11Pro

    На спецификации и лейблы тоже плевать. Должна быть накладная с чеком, где перечислено, что именно куплено, среди прочего - лицуха на винду.
    Статья "Пиратство" относится к тому "кто установил". Относится ли она к тому, кто купил в магазине и кого ввели в заблуждение?

    Не только, но и к тем, кто использовал. Но вот кто "установил" и кого "ввели в заблуждение", придется доказывать в суде, уже после штрафа (или уголовки) тому, кого поймали. Покупать (но не использовать) можно.
    Ответ написан
    2 комментария
  • Почему не работает код из js файла?

    Mike_Ro
    @Mike_Ro Куратор тега JavaScript
    Python, JS, WordPress, SEO, Bots, Adversting
    Ваш скрипт подключается в < head> и он выполнится до того, как < body> будет сформирован (т.е. body в этот момент равен null). Вам необходимо использовать скрипт после формирования dom, это можно сделать одним из следующий способов:
    - Использовать атрибут defer;
    - Дождаться загрузки страницы;
    - Подключать скрипт снизу страницы (перед закрывающим тегом body).
    Ответ написан
    3 комментария
  • Определяет ли Яндекс Метрика использование VPN?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    Вопрос: видит ли Метрика использование гражданином России VPN и IP VPN?

    При выполнении скрипта метрики на сайте, скрипт отправляет запрос с данными на сервер яши, в этот момент сервер яши видит ip того, кто отправил этот запрос, т.е. посетителя. На самом сервере можно делать что угодно с этим ip, например, прогнать его по ip-vpn базе.

    С "гражданином России" сложнее, но можно по отпечатку браузера чекать, если гражданин заходил на госуслуги, то is_сamel = true.
    Ответ написан
    Комментировать
  • Риск блокировки WhatsApp / Facebook при регистрации нескольких рабочих аккаунтов с одного IP?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    Может ли это вызвать подозрения у антиспам-систем

    Может, соблюдайте таймаут между регами. Чем больше таймаут, тем меньше шанс санкций со стороны сервиса.
    То есть в целом с одного IPшника можно но с паузами?

    Чтобы увеличить шансы, арендуйте мобильный прокси на время регистраций, для каждой реги - меняйте ip этого прокси по ссылке.
    Если сотрудники будут создавать рабочие аккаунты из офиса

    Тут интереснее, если регать будут через один и тот же браузер/компьютер, то отпечаток браузера будет одинаковый, я ставлю на то, что санкции прилетят за одинаковый отпечаток, а не за ip.

    Я бы использовал такой вариант для каждой регистрации (упрощено):
    1. Выходим через мобильный прокси (предварительно сменив ip командой (обычно, это GET запрос)).
    2. Используем первый компьютер из 4 (больше компов = больше уникальность).
    3. Используем первый браузер (chrome/ff/yandex/edge), открывать без инкогнито (важно!), но с чистым профилем. Не используйте DuckDuckGo или что то подобное, т.к. это прям совсем красная тряпка.
    4. Регаемся, закрываем браузер.
    5. Повторяем все, чтобы получилось примерно так:
    - Компьютер 1 -> Браузер 1.
    - Компьютер 2 -> Браузер 1.
    - ...
    - Компьютер 1 -> Браузер 2.
    - Компьютер 2 -> Браузер 2.
    Ответ написан
  • Как лучше поступить со страницами пагинации: сделать каждой canonical на саму себя?

    Mike_Ro
    @Mike_Ro Куратор тега Поисковая оптимизация
    Python, JS, WordPress, SEO, Bots, Adversting
    Со второй страницы и далее в title добавлены "страница 2" и т.д.

    Отлично!
    Лучше поставить index, follow?

    И каноникал установить так, чтобы каждая страница была сама на себя направлена канониклом? То есть каноникал для второй страницы прописать на нее же и так далее?

    Да.
    И правда, что лучше вообще всем страницам, не являющимся дублями, указать каноникал на них самих, потому что если будет переход с фильтрами одной и той же страницы или переход по другому адресу на ту же страницу, то робот воспримет как дубль?

    Да, для мусорных фильтров (например: site.ru/iphones?utm_source=vk) ссылаемся на саму себя, а для полезных фильтров (например: site.ru/iphones?color=red (красные айфоны)) - на фильтр. Но на страницах с полезными фильтрами нужно нормально прописать заголовки и добавить текста сверху, чтобы ПС не посчитал это дублем страницы без фильтра.
    Ответ написан
    2 комментария
  • Как правильно работать с ОРД?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    Ответ написан
    Комментировать
  • Как сделать деплой проекта, статического сайта сделанного на чистом html у которого нет баз данных?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    Как сделать деплой проекта, статического сайта сделанного на чистом html у которого нет баз данных?

    Использовать обычный ftp (узнать доступы у хостера), чтобы залить этот единственный html на сервер. Т.к. настройка деплоя для "ничего" - это преждевременная оптимизация.
    статического сайта сделанного на чистом html у которого нет баз данных

    Т.е. так же нет и серверного яп, соответственно, роутинг либо отсутствует, либо на стороне хостера (что маловероятно).
    у сайта нет index.html и файла robots.txt

    Фаил index.html был заменен главной страницей по правилам seo, где главная страница должна иметь такое же название как и домен

    Без роутинга и серверного яп, файл index.html является "главной страницей", т.к. сервер apache/nginx по умолчанию ищут индексный файл, который, внезапно так и называется - index.html, index.htm, index.php, а url адрес будет иметь вид site.ru/index.html
    Ответ написан
    Комментировать
  • Как восстановить работу тг-бота в 2026?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    и оттуда прилетают уведомления в тг-бот.

    Не надо настраивать "оттуда" так, чтобы он использовал vpn при отправке уведомлений, т.к. вы можете нарушить закон.
    Ответ написан
    Комментировать
  • Законно ли использование прокси сервера (socks5, mtproto) для личных нужд для использования телеграмма?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    149-ФЗ "Об информации, информационных технологиях ...
    Нарушит ли закон использование прокси сервера для работы телеграм на собственном впс для собственных нужд без продажи этой услуги третьим лицам?

    Без "предоставления" - не нарушает. Как именно вы это можете "предоставить" - это другой вопрос.
    Если я правильно понял закон, то нельзя предоставлять технические средства для обхода блокировок, но если я не планирую предоставлять такие услуги а пользоваться прокси для себя лично?

    На данный момент, вы все правильно поняли.
    Ответ написан
    2 комментария
  • Что это за поле при создании страницы wordpress?

    Mike_Ro
    @Mike_Ro Куратор тега WordPress
    Python, JS, WordPress, SEO, Bots, Adversting
    Достаем хрустальный шар:
    - Редактирование конкретного блока в записи, а не самой записи (вкладка Блок).
    - Чуть выше/ниже "ОТНОШЕНИЯ" имеются поля про положение иконки, ее отступов, ссылки и открытия этой ссылки в новой вкладке.

    Скорее всего, вы редактируете какой то блок с изображением-ссылкой, а раз это ссылка, то в html для ссылки имеется атрибут rel, сокращение от relationship (отношение).
    Ответ написан
    Комментировать
  • Как создать приложение Instagram?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    Ответ написан
    Комментировать
  • Может ли софт понять, что он находится за впн? В данной ситуации?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    Вопрос, может ли любой софт, запущенный на виртуальной машине, понять что он работает через впн

    Самое простое - кинуть 2 запроса, например один на 2ip.ru, второй на 2ip.io (или любые другие сервисы по определению ip), если ip разные, то...
    Ответ написан
    Комментировать
  • Можно ли получить доступ к сайту?

    Mike_Ro
    @Mike_Ro Куратор тега Python
    Python, JS, WordPress, SEO, Bots, Adversting
    на той же машине

    На винде или линуксе? Если на винде и там было все ок, то возможно, стоит смотреть в сторону ttl и tls fingerprinting Jja3/4 (возможно, dns банит все линуксы по дефолту).
    403 Forbidden, Guru meditation прилетает мгновенно при первом же driver.get(). Браузер даже не успевает начать рендерить страницу.

    Сделайте скрин страницы с "403 Forbidden, Guru meditation", может там анти-бот система вас ловит.
    Через CDP подменял WebGL Vendor/Renderer

    Через CDP нельзя изменить WebGL параметры в обычном браузере. Вы выполняете js скрипт, который переопределяет стандартное поведение встроенного объекта браузера, что вполне уверенно определяется средней анти-бот системой.

    Если бы я пытался определить бота из под докера, я бы в первую очередь смотрел на пакет шрифтов, client hints и глубину цветов дисплея.

    Но я думаю, что проблема в какой то мелочи. Попробуйте из под докера зайти на browserscan.net, и спустя 20 сек сделать скрин всей страницы, затем, сравните с тем, какие данный отображаются на том же сайте не из под докера, ищите расхождения.
    Ответ написан
    2 комментария
  • Как оптимально реализовать вкладки?

    Mike_Ro
    @Mike_Ro Куратор тега JavaScript
    Python, JS, WordPress, SEO, Bots, Adversting
    я понимаю что есть более правильный подход но не могу найти

    Примеры из гугла, найти не проблема:
    Табы (вкладки) для сайта на CSS и JavaScript – 3 с...
    JS Горизонтальные вкладки
    Ответ написан
    Комментировать
  • Что такое накрутка опыта в резюме?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    Что такое накрутка опыта в резюме?

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

    Это один из вариантов накрутки, их множество, но это уже другой вопрос.
    Ответ написан
    Комментировать
  • Как понимать такой синтаксис?

    Mike_Ro
    @Mike_Ro Куратор тега JavaScript
    Python, JS, WordPress, SEO, Bots, Adversting
    Ответ написан
    Комментировать
  • Как правильно сделать запрос на страницу для получения данных не по апи?

    Mike_Ro
    @Mike_Ro Куратор тега JavaScript
    Python, JS, WordPress, SEO, Bots, Adversting
    Несколько вариантов:
    - Блок по отсутствию заголовков или общая более сложная анти-бот система.
    - Если контент на сайте подгружается динамически, то мы увидим минимальный html с js скриптом (что собственно и произошло), т.к. fetch возвращает первый ответ сервера.
    try {
      let res = await fetch(
        'https://dzen.ru/',
        {
          headers: {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
            'Accept-Language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
          },
        },
      );
    
      if (!res.ok) {
        throw new Error(res.status);
      }
    
      console.log(await res.text());
    
    } catch (err) {
      console.error(err);
    }
    
    // <body></body><script nonce='ad618779e9500fc2a7d9bed71cf12869'>var it = {"host":"https:\u002F\u002Fsso.dzen.ru\u002Finstall?uuid=ae69654d-6b40-4184-8839-82c85f5eaedf","retpath":"https:\u002F\u002Fdzen.ru\u002F?is_autologin_ya=true","dzen":"0"};(function() { var form = document.createElement('form'); var element1 = document.createElement('input'); var element2 = document.createElement('input'); var element3 = document.createElement('input'); element1.name = 'retpath'; element1.type = 'hidden'; element1.value = it.retpath; form.appendChild(element1); element2.name = 'container'; element2.type = 'hidden'; element2.value = '1770895244.11710656.qX-ymzWyuTn9gVki.A7P1RG6nGqnkgXc_G-efyrlAO8dSE3AngEeixcNpU-0n6URKhn9Rb5gv0hp5_WD2zV5swZXnt4a3Sh9suAGvZcnJGAuYivGBF_CRsY5ObL6oz18S3HCBB4AlrMUfdb2pBcr_KCnnfC4L1Xkfz8HxFxga07tg9pohOWFDVAJq1Lpmaj2vAqhuAv9bFiNd9uWlXbA8Mhkb-y8RtrmZt5UcciU5nj5RdPPJDv8chhGRcrstadDtiyuYtIklrB1JTlV7k_kUrUTnk-M2A-9Efgh2xyEjIRwNe0edwWg5hAnp76ZO2WH-qdOZxzgI6OLrS-zyD2rNVmiTUrRMXwjmY2JJUI8SdRsBH2yKnYXm_xWH-ixffOf84KLD_ZNuB1cfzA4w3nmkh6svzaipaWCfTJoV51jW7WHdONND-Ua5GxtqJXK1rYeXrl0sLI0DSI5H0tYB6SXLljc6-xZL5vrpvq5nZZuiOHgupGUbHlmpjfUe_swd61LDP15y8qVKePI-L-vievaZ9mSfTaMCn20_VD22dTvJXS6HN1P9zuhQ3Z8X-PvVCV8HNpdObX01gko6-e1ZVaCmwaq24YwoNfYoFJNqF83nMET52ps8GcveLO-Cl_RLxeIlTvlPl92uGQbLMaHuaSHAHq0JYlO1Q0SPMLQp0yGx8sxpCp7t46nLdF3Vhbu2Wq_sDYaot8stooTl4U6OHfFx3TRyBTQvQ7mWLayIwuGQLouRpKyAlMTfS11HU53EC2LEl9-L53n_3wFPhzB3lfDRU2WSaG0T0rafQ8ubquBmcRIkytdRm8qDpwzKVmmUXFHaejmAc9XIEifofDiEG96MpIx0oc77HeGEmwmIDxldOPqCupAUsRreoZssSBJYM1Xnyb4XCGH9XeFY9a0cKPzcwImtwagP1EdNP5rz-B5g0z4FNknUkdNQsq39q4BAftIDhb2KVdmGGp1NRyj0v3LUmGATZoGk3JpFZBuGV5oDCj29ZBIYDYEsKHaOKL70mOjHmLMmSlk7vOeoluAiX422wMniAgt3e-V5mo_i-jL9tOrRocbMdcizRTX8stqinOzlut5pde54XfY1b_m3lANXXNRdgZLp6cSxnNg6w1aGBB8rSx8lXtlNrwBpaPejp0b2kpCcw-6ga6c3zuzItpwZ6O3VZUyzL85c0Bf4jdtwTJ9zLm_9j7MkAIzUCT3PTbLLzcZA5_jGQMXUg3xvQI-53RzWVuj2Z7zDXmm58WUPjn5r6kUiBr0ZumpNdYwsfC83EU5eGyMPulKmS5N4gzyxi1_XVxYhrDg0OQGUHs5_0uRf-Lh5edlzoM4mzLEZiapfaqsEnme-yVkwDFgSM7-i3CsVsLKreuDcfxwdB80u-7N5OM5ppZA3XjerasaS6mA4L7CvOcspPHUMXrwi-z_jsWRnEia3z7510GCpYbml6-WY_YdQOj_Q0_HtLF7i2G3lly32ieSrzg6EvrPXPvaQfsS3eX1FTGk.XdnKkcqYYirqyGrd38wg3g'; form.appendChild(element2); element3.name = 'dzen'; element3.type = 'hidden'; element3.value = it.dzen; form.appendChild(element3); form.method = 'POST'; form.action = it.host; document.body.appendChild(form); form.submit();})();</script>

    Я хочу получать список новостей с сайта, но при фетче страницы, я ничего не получаю в ответ.

    В отладчике браузера смотрите, куда страница шлет запросы, смотрите на заголовки и прочие данные, которые она шлет, затем пытайтесь слать аналогичные запросы из под ноды.
    В примере с апи всё работает.

    Для быстрой проверки используйте терминал, например с curl (или curl.exe для винды):
    $ curl https://dzen.ru
    $
    $ curl https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits
    [
      {
        "sha": "d78b01e9833009fab534462e05c03cffc51bf0e3",
        "node_id": "C_kwDOBY7uftoAKGQ3OGIwMWU5ODMzMDA5ZmFiNTM0NDYyZTA1YzAzY2ZmYzUxYmYwZTM",
        "commit": {
          "author": {
            "name": "Stanislav (Stanley) Modrak",
            "email": "44023416+smith558@users.noreply.github.com",
            "date": "2025-11-20T20:55:50Z"
          },
          "committer": {
            "name": "GitHub",
            "email": "noreply@github.com",
            "date": "2025-11-20T20:55:50Z"
          },
          "message": "Merge pull request #3906 from cathoderay/master\n\nMinor grammar improvement",
          "tree": {
            "sha": "e7064bb8aaef800dbe406e245bbfe0e69ec6d270",
            "url": "https://api.github.com/repos/javascript-tutorial/en.javascript.info/git/trees/e7064bb8aaef800dbe406e245bbfe0e69ec6d270"
          },
          "url": "https://api.github.com/repos/javascript-tutorial/en.javascript.info/git/commits/d78b01e9833009fab534462e05c03cffc51bf0e3",
          "comment_count": 0,
          "verification": {
            "verified": true,
            "reason": "valid",
            "signature": "-----BEGIN PGP SIGNATURE-----\n\nwsFcBAABCAAQBQJpH4BWCRC1aQ7uu5UhlAAAntUQAFeFvVv0p3ncxrNhfuVopAmE\nNmlXv+VtX2eYBLDzZn24N5fLme9wYT5sE2Ib4cyJgtNRWf+iYv66MqBoIu6oqMYE\n26y7Ylhjp3gr6/yUjfFLTvhZqOtLvddY7kH8sMH+r0T+MEvqCbwv30oKWdx39sa2\nTYvBjarpLpcdOm6k/amkDveLj148gehKZB1xeg5VgSDIdwl9cFAWLLlyf4s9dkCB\niX1+82NLR1uWT23WmflBClaP8Q+MH0dLe79KK9Aa8MV0ZuN2KQnhZ/0ICBQUAT7k\na5ks2lFJv+35S/mFjYxCIWGeHf6ntsa7NnJo/tDtSFOMVLwxZ17KeJQjBt5gvFyo\nW1xOpgCpeFL3V9fC567QZ4h2UG1pAn/3Susc6WfG7A4WsGR2La7IuzP2XbcZAN1+\nksewNCSumhWtXsmT9rdzBiDB7mchWljJKzXOAcwTL3rsenpUeLVeexU19qzdUZ4b\nLMjLbt1u+xauX85+k5OW8r/9jiz+gE3B6g3SzNY9ktAxVVQzPq83u22Z27Cm6asL\n5BnDhKIXNA+9UXCVcUWCAsSuxoV4Hgeh6htWqGBEZPWUGHUUt0l4EybnMQRtYn4P\nxTyqyIQK1rioU5Wk/4LrQ9YwPgBgNj1+FV/idunDuYcZm02N7zhCXZu9PLx2MU4u\ndwszDjfzlv5FsMNt5NRz\n=hmS8\n-----END PGP SIGNATURE-----\n",
            "payload": "tree e7064bb8aaef800dbe406e245bbfe0e69ec6d270\nparent 5e893cffce8e2346d4e50926d5148c70af172533\nparent 9ef986e9cb68073eef1c6a9ac076ec2cb3b95637\nauthor Stanislav (Stanley) Modrak <44023416+smith558@users.noreply.github.com> 1763672150 +0000\ncommitter GitHub <noreply@github.com> 1763672150 +0000\n\nMerge pull request #3906 from cathoderay/master\n\nMinor grammar improvement",
            "verified_at": "2025-11-20T20:55:50Z"
          }
    ...
    Ответ написан
    Комментировать
  • Как оптимизировать или создать правильно mysql запрос?

    Mike_Ro
    @Mike_Ro
    Python, JS, WordPress, SEO, Bots, Adversting
    (select count(id) from orders_items where order_id=orders.order_id)=1

    Запрос будет выполняться для каждой строки, которую найдет бд (10000 заказов - 10000 выполнится поиск) - это не очень эффективно...

    Можно попробовать найти товар в orders_items, затем присоединить таблицу orders, затем использовать not exist, чтобы убедиться, что в заказе нет других записей:
    SELECT
        o.order_id,
        o.shipment_date
    FROM
        orders_items oi
    
            -- Присоединяем таблицу заказов, чтобы получить доступ к дате и статусу.
            INNER JOIN
        orders o ON oi.order_id = o.order_id
    WHERE
    
        -- Находим строки конкретного товара.
        oi.sku = '$sku'
      AND oi.quantity = 1
    
      -- Фильтры таблицы заказов.
      AND o.place_order = 0
      
      -- Отсекаем лишнее по дате.
      AND o.shipment_date <= (NOW() - INTERVAL 20 DAY)
    
      -- В этом заказе не должно быть других позиций.
      AND NOT EXISTS (
        SELECT 1
        FROM orders_items oi_check
        WHERE oi_check.order_id = oi.order_id
    
          -- Ищем любую запись с тем же order_id, но другим id.
          AND oi_check.id <> oi.id
    )
    ORDER BY
        o.id DESC
        LIMIT 1;

    P.S. этот запрос будет производительный лишь в том случае, если у вас есть индексы. Проверьте наличие индексов у orders_items(sku) (лучше составной (sku, quantity)), orders_items(order_id) и orders(order_id).
    Ответ написан
    Комментировать