Is this query optimised? - Mutual follows - mysql

Is this query optimised?
I'm trying to get the list of people personA follows who follow personB.
Few thousand of rows right now in the table but growing fast.
Want to make sure the query is performant enough for mysql.
Query:
select
*
from
(
select
*
from
creator_followers cf
where
cf.follower_user_id = 'personA'
and cf.current_active = 1
and cf.current_following = 1
) as fo
join creator_followers cf
where
fo.creator_user_id = cf.follower_user_id
and cf.creator_user_id = 'personB'
and cf.current_following = 1
and cf.current_active = 1
order by
cf.created_at desc
limit
10 offset 0;
Schema:
create table social.creator_followers
(
creator_user_id varchar(16) charset utf8 null,
follower_user_id varchar(16) charset utf8 null,
current_following bit null,
current_active bit null,
created_at bigint null,
id bigint auto_increment
primary key
)

It seems that it must be
SELECT *
FROM creator_followers cf1
join creator_followers cf2 ON cf1.creator_user_id = cf2.follower_user_id
where cf1.follower_user_id = 'personA'
and cf2.creator_user_id = 'personB'
and cf1.current_active = 1
and cf1.current_following = 1
and cf2.current_following = 1
and cf2.current_active = 1
order by cf2.created_at desc
limit 10 offset 0;

Based on a Comment, this might provide another speedup. Replace
id bigint auto_increment
primary key
with
PRIMARY KEY(creator_user_id, follower_user_id)

Related

Get value of mySQL query grouped by id

I want to know an efficient way to solve the following query. Essentially I have the following two classes
CREATE TABLE `example`.`doc` (
`id` INT NOT NULL AUTO_INCREMENT,
`uuid` INT NOT NULL,
`creator` VARCHAR(32) NOT NULL,
PRIMARY KEY (`id`);
CREATE TABLE `example`.`pic` (
`id` INT NOT NULL AUTO_INCREMENT,
`docuuid` INT NOT NULL,
`taken_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
`lat` DECIMAL(3,10),
`lon` DECIMAL(3,10),
PRIMARY KEY (`id`);
this two tables are related by uuid (I know this is not the best idea to link two tables, but the table is like this). uuid is unique per doc. With the following query
SELECT
`doc`.`id` AS `docId`,
`doc`.`uuid` AS `uuid`,
`doc`.`creator` AS `creator`,
COUNT(`pic`.`id`) AS `pics`,
MIN(`pic`.`taken_at`) AS `min_date`,
MAX(`pic`.`taken_at`) AS `max_date`
FROM
`doc` INNER JOIN
`pic` ON (`doc`.`uuid` = `pic`.`docuuid`)
WHERE (
`pic`.`docuuid` IS NOT NULL AND
`doc`.`uuid` IS NOT NULL)
GROUP BY `doc`.`uuid`
I get, for each doc, the date at witch the first and last pics was taken. Additionally I want to get in this query, for each doc, the latitude and longitude of the first and last pic taken at that doc.
For example, If I have
doc1 = (id=0, uuid=1)
doc2 = (id=1, uuid=2)
pic1 = (taken_at=2021-01-01, docuuid=1, lat=1, lon=2)
pic2 = (taken_at=2021-01-02, docuuid=1, lat=3, lon=4)
pic3 = (taken_at=2021-01-03, docuuid=2, lat=5, lon=6)
pic4 = (taken_at=2021-01-04, docuuid=2, lat=7, lon=8)
pic5 = (taken_at=2021-01-05, docuuid=2, lat=9, lon=10)
then I want to get for doc1 minLat=1, minLon=2, maxLat=3, maxLon=4 and for doc2 minLat=5, minLon=6, maxLat=9, maxLon=10
You mat continue by joining the results of your current query with the pics table and extracting the desired details of each pic, I've included a sample below:
SELECT
t.*,
earliest_pic.lat as minLat,
earliest_pic.lon as minLon,
latest_pic.lat as maxLat,
latest_pic.lon as maxLon
FROM
(
SELECT
`doc`.`id` AS `docId`,
`doc`.`uuid` AS `uuid`,
`doc`.`creator` AS `creator`,
COUNT(`pic`.`id`) AS `pics`,
MIN(`pic`.`taken_at`) AS `min_date`,
MAX(`pic`.`taken_at`) AS `max_date`
FROM
`doc` INNER JOIN
`pic` ON (`doc`.`uuid` = `pic`.`docuuid`)
GROUP BY `doc`.`uuid`
) AS t
INNER JOIN `pic` as earliest_pic ON earliest_pic.taken_at = t.min_date AND
earliest_pic.docuuid = t.docId
INNER JOIN `pic` as latest_pic ON latest_pic.taken_at = t.max_date AND
latest_pic.docuuid = t.docId
Let me know if this works for you

How to prevent duplicate entry key when update

Problem explain
I won't update the last primary key of the 3 primary key concatenate. But the problem is sometimes the first and second primary key was the same for multiple records. And in this case, when I set my new value I have a duplicate entry key even I use sub-request to avoid that problem.
Some Code
Schemas
create table llx_element_contact
(
rowid int auto_increment
primary key,
datecreate datetime null,
statut smallint default 5 null,
element_id int not null,
fk_c_type_contact int not null,
fk_socpeople int not null,
constraint idx_element_contact_idx1
unique (element_id, fk_c_type_contact, fk_socpeople)
)
Update request
this request return duplicate key error
update llx_element_contact lec
set lec.fk_socpeople = 64
where
-- Try to avoid the error by non including the values that are the same
(select count(*)
from llx_element_contact ec
where ec.fk_socpeople = 64
and ec.element_id = lec.element_id
and ec.fk_c_type_contact = lec.fk_c_type_contact) = 0
Test data
rowid, datecreate, statut, element_id, fk_c_type_contact, fk_sockpeople
65,2015-08-31 18:59:18,4,65,160,30
66,2015-08-31 18:59:18,4,66,159,12
67,2015-08-31 18:59:18,4,67,160,12
15283,2016-03-23 11:47:15,4,6404,160,39
15284,2016-03-23 11:51:30,4,6404,160,58
You should check only two other members of unique constraint as you're trying to assign the same value to the 3d member. No more then one row with the same two members must exist.
update llx_element_contact lec
set lec.fk_socpeople = 64
where
-- Try to avoid the error by non including the values that are the same
(select count(*)
from llx_element_contact ec
where ec.element_id = lec.element_id
and ec.fk_c_type_contact = lec.fk_c_type_contact) <=1
or
update llx_element_contact lec
set lec.fk_socpeople = 64
where
-- Try to avoid the error by non including the values that are the same
not exists (select 1
from llx_element_contact ec
where ec.element_id = lec.element_id
and ec.fk_c_type_contact = lec.fk_c_type_contact
and lec.fk_socpeople != ec.fk_socpeople)
You can use:
You can prevent the unique conflict using left join to check that the corresponding row doesn't already exist:
update llx_element_contact lec left join
(select element_id, fk_c_type_contact
from llx_element_contact lec2
where lec2.fk_socpeople = 64
group by element_id, fk_c_type_contact
) lec2
using (element_id, fk_c_type_contact)
set lec.fk_socpeople = 64
where lec2.element_id is null;
Your query has additional logic in it that is not explained. It is not necessary for what you are asking.
WITH cte AS (
SELECT rowid,
SUM(fk_socpeople = 64) OVER (PARTITION BY element_id, fk_c_type_contact) u_flag,
ROW_NUMBER() OVER (PARTITION BY element_id, fk_c_type_contact ORDER BY datecreate DESC) u_rn
FROM llx_element_contact
)
update llx_element_contact lec
JOIN cte USING (rowid)
set lec.fk_socpeople = 64
where cte.u_flag = 0
AND cte.u_rn = 1
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=08e20328ccc6187716084ce9d78816b0

How do I Union with an Inner Join

I have three separate tables, bs_products, td_products, and fv_products.
SELECT
bso.order_id, bso.order_num, bso.Salesman, bso.salesman_name, bso.date, bso.status,
bsp.product_id, bsp.product_branch, bsp.product_name, bsp.description, bsp.vatable, bsp.critical_stock,
bsp.quantity, bsp.sell_price, bsp.category_id, bsp.expiry_date, bsp.date, bsp.isEmpty, bsp.empties,
bss.sws_id, bss.sws_proname, bss.sws_isEmpty, bss.sws_category, bss.sws_unitprice, bss.sws_prodesc,
bss.sws_proexp, bss.sws_vat, bss.sws_number, bss.date, bss.sws_salesman, bss.sws_route, bss.sws_smname,
bss.sws_driver, bss.sws_plate, bss.sws_vehicle, bss.sws_load, bss.sws_productid, bss.sws_quantity
FROM bs_orders as bso INNER JOIN bs_products as bsp
INNER JOIN bs_sws as bss WHERE status = 'Completed'
AND bso.date = '11/30/2016'
AND bso.order_num = bss.sws_number
AND bss.sws_productid = bsp.product_id
UNION
SELECT
tdo.order_id, tdo.order_num, tdo.Salesman, tdo.salesman_name, tdo.date, tdo.status,
tdp.product_id, tdp.product_branch, tdp.product_name, tdp.description, tdp.vatable, tdp.critical_stock,
tdp.quantity, tdp.sell_price, tdp.category_id, tdp.expiry_date, tdp.date, tdp.isEmpty, tdp.empties,
tds.sws_id, tds.sws_proname, tds.sws_isEmpty, tds.sws_category, tds.sws_unitprice, tds.sws_prodesc,
tds.sws_proexp, tds.sws_vat, tds.sws_number, tds.date, tds.sws_salesman, tds.sws_route, tds.sws_smname,
tds.sws_driver, tds.sws_plate, tds.sws_vehicle, tds.sws_load, tds.sws_productid, tds.sws_quantity
FROM td_orders as tdo INNER JOIN td_products as tdp
INNER JOIN td_sws as tds WHERE status = 'Completed'
AND tdo.date = '11/30/2016'
AND tdo.order_num = tds.sws_number
AND tds.sws_productid = tdp.product_id
UNION
SELECT
fvo.order_id, fvo.order_num, fvo.Salesman, fvo.salesman_name, fvo.date, fvo.status,
fvp.product_id, fvp.product_branch, fvp.product_name, fvp.description, fvp.vatable, fvp.critical_stock,
fvp.quantity, fvp.sell_price, fvp.category_id, fvp.expiry_date, fvp.date, fvp.isEmpty, fvp.empties,
fvs.sws_id, fvs.sws_proname, fvs.sws_isEmpty, fvs.sws_category, fvs.sws_unitprice, fvs.sws_prodesc,
fvs.sws_proexp, fvs.sws_vat, fvs.sws_number, fvs.date, fvs.sws_salesman, fvs.sws_route, fvs.sws_smname,
fvs.sws_driver, fvs.sws_plate, fvs.sws_vehicle, fvs.sws_load, fvs.sws_productid, fvs.sws_quantity
FROM fv_orders as fvo INNER JOIN fv_products as fvp
INNER JOIN fv_sws as fvs WHERE status = 'Completed'
AND fvo.date = '11/30/2016'
AND fvo.order_num = fvs.sws_number
AND fvs.sws_productid = fvp.product_id
I tried running this on phpMyAdmin but it gives me an error of
1221 - Incorrect usage of UNION and LIMIT
What is the correct query for this?
_orders Table
order_id (Primary) int(11)
order_num int(255)
Salesman varchar(255)
salesman_name varchar(255)
date varchar(255)
status varchar(255)
_products Table
product_id (Primary) int(11)
product_branch varchar(255)
product_name varchar(255)
description varchar(255)
vatable tinyint(1)
critical_stock int(11)
quantity int(11)
sell_price double
category_id int(11)
expiry_date varchar(255)
date varchar(255)
isEmpty tinyint(1)
empties int(11)
_sws Table
sws_id (Primary) int(11) No
sws_proname varchar(255)
sws_isEmpty tinyint(1)
sws_category int(11)
sws_unitprice double
sws_prodesc varchar(255)
sws_proexp varchar(255)
sws_vat tinyint(1)
sws_number int(255)
date varchar(255)
sws_salesman varchar(255)
sws_route varchar(255)
sws_smname varchar(255)
sws_driver varchar(255)
sws_plate varchar(255)
sws_vehicle varchar(255)
sws_load int(255)
sws_productid int(255)
sws_quantity int(255)
When using UNION the number of columns that are in each subquery has to be the same and they have to be of the same data type.
You will need to adjust your query so that you are not using * but defining each column from each table.
See the following for more info:
http://www.mysqltutorial.org/sql-union-mysql.aspx
https://dev.mysql.com/doc/refman/5.7/en/union.html
There are some rules that you need to follow in order to use the UNION operator:
The number of columns appears in the corresponding SELECT statements must be equal.
The columns appear in the corresponding positions of each SELECT statement must have the same data type or, at least, convertible data type.
You need to re-think you plan.
To do a union you need fields of the same names, and data types. You can't simply select * and expect different tables to combine in a single result set.
You may need to change names or add dummy columns in different parts of the select to make it work.
If you post the table structures and field names people may be able to help you more.

How to combine two SQL queries in one query

I have two queries which are unrelated to each other, first query returns 4 column whereas the second one returns only 1 column.
so how to combine it?
query 1-
$sql = "select postlist.* from postlist order by postlist.id desc ";
query 2-
$sql1 = "select count (commentlist.id) as 'comments',commentlist.id,commentlist.name,commentlist.comment from postlist,commentlist where postlist.id=commentlist.post_id";
current query-
$sql = "select postlist.*, count (commentlist.id) as 'comments' from postlist LEFT JOIN commentlist ON postlist.id=commentlist.post_id order by postlist.id desc ";
Basically, I want to return all records from postlist, whether the commentlist table has any related comments or not.
Here is a database design
drop table if exists postlist;
create table postlist (
id integer not null primary key autoincrement,
post varchar(1000) not null,
name varchar(80) not null,
title varchar(80) not null
);
drop table if exists commentlist;
create table commentlist (
id integer not null primary key autoincrement,
post_id integer not null,
comment varchar(80) not null,
name varchar(80) not null
);
The get() will cast it to a Collection, that is a lot more powerful than an array. You can append it, iterate over it and more.
Have a bash at that. Hopefully it should be what you need: http://laravel.com/docs/4.2/eloquent#collections
$items = DB::select($sql)->get();
$items1 = DB::select($sql1)->get();
$items = items->toArray();
$items1 = items1->toArray();
$items = array_merge($items, $items1);

Transferring data from one table to another, some relational columns

Table 1 - this table is completely populated from an XLSX file...
Tables 2 and 3 - contain 1-1 references for a couple of the columns in the final table.
Table 3 - the on I am trying to get populated with first three tables....
As you can see, the tables are sensible, there is no einsteinic equations or conversions going on. Here is the code that I have already tried, unsuccessfully:
INSERT INTO att_oem_orders SELECT NULL, ost.om_or_po, (SELECT j.job_id FROM jobs j WHERE j.project_number = project_no), NULL, (SELECT ao.id FROM att_oem WHERE ao.item_no = item_no), ost.po_number, (SELECT ol.id FROM order_lsc WHERE STATUS = ol.line_status_code), ost.ordered_date, ost.shipment_date, NULL, NULL, ost.item_qty, NULL, NULL, NULL, NULL, ost.shipping_to, ost.tracking_number, ost.carrier) FROM oem_temp_sync WHERE ost.item_qty > 0
Try limiting the number of possible values to put into a field using FIRST() like so:
INSERT INTO att_oem_orders SELECT
NULL,
ost.om_or_po,
(SELECT FIRST(j.job_id) FROM jobs j WHERE j.project_number = project_no),
NULL,
(SELECT FIRST(ao.id) FROM att_oem WHERE ao.item_no = item_no),
ost.po_number,
(SELECT FIRST(ol.id) FROM order_lsc WHERE STATUS = ol.line_status_code),
ost.ordered_date,
ost.shipment_date,
NULL,
NULL,
ost.item_qty,
NULL,
NULL,
NULL,
NULL,
ost.shipping_to,
ost.tracking_number,
ost.carrier
FROM oem_temp_sync WHERE ost.item_qty > 0
You also appear to have an extra ) just before FROM
With a little bit of help from everyone, I've found a few errors and fixed a few sub-queries. Here is the final version:
INSERT INTO att_oem_orders
SELECT
NULL,
ost.om_or_po,
(SELECT
FIRST(j.id)
FROM
jobs j
WHERE j.project_number = ost.project_no),
NULL,
(SELECT
FIRST(ao.id)
FROM
att_oem ao
WHERE ao.item_no = ost.item_no),
ost.po_number,
(SELECT
FIRST(ol.id)
FROM
att_oem_lsc ol
WHERE ol.status = ost.line_status_code),
ost.ordered_date,
ost.shipment_date,
NULL,
NULL,
ost.item_qty,
NULL,
NULL,
NULL,
NULL,
ost.ship_to,
ost.tracking_no,
ost.carrier
FROM
oem_sync_temp ost
WHERE ost.item_qty > 0