Query on MySQL with multiple joins - mysql

I use MySQL 5.7 and have the following tables:
documents:
---------------------------------------------------------------
id collection_id numeric_shelfmark shelfmark
---------------------------------------------------------------
1 kbt y024 Y 24
---------------------------------------------------------------
collections:
---------------------------------------------------------------
id name location
---------------------------------------------------------------
kbt kantonb thur Thurgau
gbt lorem ipsum
----------------------------------------------------------------
subprojects_x_documents
-----------------------------------------------------------------
subproject_id document_id
-----------------------------------------------------------------
foo 1
-----------------------------------------------------------------
documents_revisions
-----------------------------------------------------------------
document_id updated_at numeric_shelfmark shelfmark latest
-----------------------------------------------------------------
1 2016-06-22 10:32:01 y024 Y 24 0
1 2017-09-19 09:19:17 z024 Z 24 1
------------------------------------------------------------------
With the following SELECT query I could manage to get a list of the documents associated with the subproject and collections:
SELECT `documents`.`id`, `documents`.`collection_id`,
`documents`.`numeric_shelfmark`, `shelfmark`, `location`, `name`
FROM (`documents`)
JOIN `collections` ON `documents`.`collection_id` = `collections`.`id`
JOIN `subprojects_x_documents` ON `documents`.`id` =
`subprojects_x_documents`.`document_id`WHERE
`subprojects_x_documents`.`subproject_id` = 'stgall_lotterie'
ORDER BY `location`, `name`, `documents`.`sort_order`, `numeric_shelfmark`
Now, I'm trying to get the latest ("documents_revisions.latest" = 1) revision of document with:
SELECT `documents`.`id`, `documents`.`collection_id`,
`documents`.`numeric_shelfmark`, `documents`.`shelfmark`, `location`,
name`FROM (`documents`)JOIN `collections` ON
`documents`.`collection_id` = `collections`.`id`JOIN
`documents_revisions` ON `documents_revisions`.`document_id` =
`documents`.`id`JOIN `subprojects_x_documents` ON `documents`.`id` =
`subprojects_x_documents`.`document_id` WHERE
`subprojects_x_documents`.`subproject_id` = 'stgall_lotterie' AND
`documents_revisions`.`latest` = 1 ORDER BY `location`, `name`,
`documents`.`sort_order`, `numeric_shelfmark`
But this query returns the same list of documents as before and ignores the documents_revisions.latest" = 1 part.
When I update the query to perform the operation on documents_revisons table instead of documents table:
SELECT `documents`.`id`, `documents`.`collection_id`,
documents.numeric_shelfmark, documents.shelfmark, location,
nameFROM (documents_revisions)JOIN collections ON
documents.collection_id = collections.idJOIN
documents_revisions ON documents_revisions.document_id =
documents.idJOIN subprojects_x_documents ON documents.id =
subprojects_x_documents.document_id WHERE
subprojects_x_documents.subproject_id = 'stgall_lotterie' AND
documents_revisions.latest = 1 ORDER BY location, name,
documents.sort_order, numeric_shelfmark
I get the error message: "Not unique table/alias: 'documents_revisions'"

Your table is called documents, not document

Ok, after some tweaking I got my result with:
SELECT documents_revisions.document_id,
documents_revisions.collection_id,
documents_revisions.numeric_shelfmark,
documents_revisions.shelfmark, location, nameFROM
(documents_revisions)JOIN collections ON
documents_revisions.collection_id = collections.id JOIN
subprojects_x_documents ON documents_revisions.document_id =
subprojects_x_documents.document_id WHERE
subprojects_x_documents.subproject_id = 'stgall_lotterie' AND
documents_revisions.latest = 1 ORDER BY location, name,
numeric_shelfmark

Related

Select range date from and to and also select specific id

I want to select a date range with specific provider ID and this query should print 2 data only since there's only 2 row with provider id = 1
SQL Query:
SELECT logs_tb.logs_id
,logs_tb.time_in
,logs_tb.status
,logs_tb.provider_id
,users_tb.user_first_name
,users_tb.user_last_name
,users_tb.user_contactno
,users_tb.user_city
,users_tb.user_avatar
,users_tb.user_email
,users_tb.user_contactno
,users_tb.user_uuid
FROM logs_tb
,users_tb
WHERE logs_tb.provider_id = 1
AND logs_tb.log_date BETWEEN '2022-03-25' AND '2022-03-26'
ORDER BY logs_tb.logs_id desc;
Table:
Output:
I used ON condition, thank you M.Hermant
Query:
SELECT logs_tb.logs_id, logs_tb.time_in, logs_tb.status, logs_tb.provider_id, users_tb.user_first_name, users_tb.user_last_name, users_tb.user_contactno, users_tb.user_city, users_tb.user_avatar, users_tb.user_email, users_tb.user_contactno, users_tb.user_uuid
FROM users_tb
INNER JOIN logs_tb
ON users_tb.user_id = logs_tb.user_id
WHERE (logs_tb.log_date BETWEEN '2022-03-25' AND '2022-03-26') AND logs_tb.provider_id = 1
ORDER BY logs_tb.log_date desc;
Output:

MySql Retrieving Data from multiple Tables then Insert limited values In another table

I have many tables with the same structure for each of my costumers.
All information are distinct for each table.
For some reason, I need to create some temporary table with the same structure with 200 values everytime I run.
So let's assume I have 3 tables.
Costumer1, Costumer2, Costumer3.
All those tables have id, user_name, contact_name, contact_email, sent1, sent2, sent3, sent4, status.
I need some query to put inside costumer_tmp, only 200 values in total, from all those 3 tables, everytime I run the script. And everytime I run cant repeat the last values I got before.
So for example:
Costumer1
id = 29
user_name = test1
contact_name = contact1
contact_email = contact1#mail.com
sent1 = yes
sent2 = no
sent3 = no
sent4 = no
status = In Progress
Costumer2
id = 37
user_name = test2
contact_name = contact123
contact_email = contact123#mail.com
sent1 = yes
sent2 = no
sent3 = no
sent4 = no
status = In Progress
Costumer3
id = 87
user_name = test3
contact_name = contact231
contact_email = contact231#mail.com
sent1 = yes
sent2 = no
sent3 = no
sent4 = no
status = In Progress
How to Insert on costumer_tmp only 2 records of those 3 and next time I run the script don't repeat those 2 records, just insert only 1 record remaining.
Your requirement is a bit weird, but if I understand weel, how about something like : (not tested)
insert into costumer_tmp
select * from Costumer1 one where one.id not in (select id from costumer_tmp)
union all
select * from Costumer2 two where two.id not in (select id from costumer_tmp)
union all
select * from Costumer3 three where three.id not in (select id from costumer_tmp) LIMIT 200

SQL request with a joining condition

SELECT mairie.city, permission.permission
FROM permission , user_mairie, mairie
WHERE user_mairie.iduser = 1
AND user_mairie.idmairie = mairie.idmairie
CASE user_mairie.idrole
WHEN 2 THEN
JOIN user_permission
ON user_permission.idpermission = permission.idpermission
AND user_permission.iduser = user_mairie.iduser
END
ORDER BY mairie.idmairie, permission.idpermission
I'm trying to get the permissions of a specific user if this user has a specific role.
A "mairie" is a "town hall" in french.
A user can have different roles in different "mairie"s.
If the user on user_mairie has idrole = 2, then we have to go to the table "user_permission" to get it's permissions.
If the user on user_mairie has idrole = 1 then he is admin and he has ALL permissions, but the permissions are not written in user_permission (because user_permission is used only for idrole = 2).
What I want is for example :
if the user_mairie.idrole = 1 :
SELECT *
FROM permission
if the user_mairie.idrole = 2
SELECT *
FROM permission, user_permission
WHERE user_mairie.idrole = 2
AND user_mairie.iduser = user_permission.iduser
AND user_permission.idpermission = permission.idpermission
I could do this using my programming language and making 2 requests, but I'd like to know if in pure SQL, this issue is solvable.
Some datas:
Table permission:
idpermission | permission
1 | permission_1
2 | permission_2
3 | permission_3
Table user_mairie :
iduser | idmairie | idrole
1 | 1 | 1
1 | 2 | 2
Table user_permission :
iduser | idpermission | idmairie
1 | 1 | 2
1 | 3 | 2
Table mairie :
idmarie | city
1 | mairie_1
2 | mairie_2
The result I want (for a given iduser = 1) would be :
mairie_1 : permission_1, permission_2, permission_3
mairie_2 : permission_1, permission_3
Thanks for reading me.
SQL DEMO
First you start with all marie and all permissions
SELECT um.idrole, m.city, p.permission
FROM user_mairie um
JOIN mairie m
ON um.idmairie = m.idmairie
CROSS JOIN permission p
WHERE um.iduser = 1
Now you remove the permission you dont have
WHERE um.iduser = 1
AND ( um.idrole = 1 -- have all permission
OR EXISTS (SELECT up.idpermission
FROM user_permission up
WHERE up.iduser = um.iduser
AND up.idpermission = p.idpermission )
)
OUTPUT
I think you really want LEFT JOIN:
SELECT . . .
FROM user_mairie LEFT um
user_permission up
ON um.iduser = up.iduser LEFT JOIN
permission p
ON up.idpermission = p.idpermission OR
um.idrole = 1 ;
You may not want the condition on idrole.
This gets permissions only for id roles "2".
Notes:
List all the columns you want in the SELECT.
Learn to use proper, explicit, standard JOIN syntax. Never use commas in the FROM clause.
Table aliases make the query easier to write and to read.
Use LEFT JOIN so you can keep all the rows, even when there are no permissions.

How to select static values on mysql select query?

I am new to mysql, here i am trying to get data from database table.
select id,txnid,amount,status from txn_details;
With above query Getting data successfully but status column getting 0 or 1 or 2, but i want 0 as failed, 1 as success and 2 as not processed.
How to change my query?
You can use a case
select id, txnid, amount,
case when status = 0 then 'failed'
when status = 1 then 'success'
else 'not processed'
end as status
from txn_details;
We can use an expression in the SELECT list. It could be a searched CASE expression e.g.
SELECT CASE t.status
WHEN 0 THEN 'failed'
WHEN 1 THEN 'success'
WHEN 2 THEN 'not processed'
ELSE 'unknown'
END AS status_name
, t.status
, t.amount
, t.txnid
FROM txn_details t
This approach is ANSI-92 standards compliant, and will work in most relational databases.
There are some other MySQL specific alternatives, such as the ELT function ...
SELECT ELT(t.status+1,'failed','success','not processed') AS status_name
, t.status
, t.amount
, t.txnid
FROM txn_details t
https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_elt
If you prefer a central point of maintenance (ie you prefer not to recode all your queries when a new status comes along) you could create a status table and either use a join or sub query to get the values, alternatively you could create a function, for example
drop table if exists txn_details,txn_status;
create table txn_details(id int, txnid int, amount int , status int);
insert into txn_details values
(1,1,10,1),(2,1,10,2),(3,1,10,4);
create table txn_status (id int, statusval varchar(20));
insert into txn_status values
(1,'success'),(2,'not processed'), (3,'failed');
drop function if exists f;
delimiter $$
create function f(instatus int)
returns varchar(20)
begin
declare rval varchar(20);
return (select
case when instatus = 1 then 'success'
when instatus = 2 then 'not processed'
when instatus = 3 then 'failed'
else 'Unknown'
end
);
select t.*,coalesce(ts.statusval,'Unknown') status
from txn_details t
left join txn_status ts on ts.id = t.status;
select t.*,coalesce((select statusval from txn_status ts where ts.id = t.status),'Unknown') status
from txn_details t;
Note the use of coalesce in case a status is not found.
Both produce this result
+------+-------+--------+--------+---------------+
| id | txnid | amount | status | status |
+------+-------+--------+--------+---------------+
| 1 | 1 | 10 | 1 | success |
| 2 | 1 | 10 | 2 | not processed |
| 3 | 1 | 10 | 4 | Unknown |
+------+-------+--------+--------+---------------+
3 rows in set (0.00 sec)
Using the function like this
select t.*, f(status) as status
from txn_details t;
also produces the same result.
Of course using a status table or a function means you have to communicate their availability and enforce their use.
I would also consider the using a foreign key constraint in txn_details to cut down on the number of unknown values and put procedures in place to stop people adding new status codes at will without going through change control
The following query would work. It uses CASE ... END to determine and return values for the virtual column status.
SELECT id,txnid,amount,
CASE
WHEN status = 0 THEN 'failed'
WHEN status = 1 THEN 'success'
WHEN status= 2 THEN 'not processed'
END AS status
FROM txn_details;

joining tables takes very long time symfony 2.7

I have the following query which takes more than 20 secs (20138ms) to return the results.
$locale = 'en'; // test
$query = $this->getEntityManager()->createQuery('
SELECT
product.id, product.productnr, ProductGrp.productgrp' . $locale . ', Criteria.criteria'.$locale.'
FROM
Productbundle:product product
JOIN
Productbundle:Criteria Criteria WITH Criteria.criteriaid = product.criteriaid
JOIN
Productbundle:ProductGrp ProductGrp WITH ProductGrp.partgrpid = product.partgrpid
WHERE
product.productnr =:productnr
')
->setMaxResults(1)
->setParameter('productnr', $productnr)
->getResult();
when I ran the query from "runnable query" it took about 20 secs (20.7809) in phpmyadmin.
runnable query :
SELECT o0_.id AS id0, o0_.productnr AS productnr1, o1_.productgrpen AS productgrpen2, o2_.criteriaen AS criteriaen3
FROM product o0_
INNER JOIN Criteria o2_ ON (o2_.criteriaid = o0_.criteriaid)
INNER JOIN ProductGrp o1_ ON (o1_.partgrpid = o0_.partgrpid)
WHERE o0_.productnr = 'ABC1234'
LIMIT 1;
However when I ran the following code in phpmyadmin it takes less than 2seconds to return the results
SELECT product.id, product.productnr,ProductGrp.productgrpen ,Criteria.criteriaen
FROM `product`
INNER JOIN ProductGrp ON ProductGrp.partgrpid = product.partgrpid
INNER JOIN Criteria ON Criteria.criteriaid = product.criteriaid
Where productnr = 'ABC1234'
LIMIT 1
table size
-------------------------------
|Product | over 5mill rows |
-------------------------------
|ProductGrp | over 200 rows |
-------------------------------
|Criteria | over 600 rows |
-------------------------------
Symfony version : 2.7
Indexes although not listed, I would suggest the following
table indexed on
Product (productnr, id, criteriaid, partgrpid )
Criteria (criteriaid ) -- would expect as primary key
ProductGrp (partgrpid ) -- also would expect
Also, how many "locale" string version columns do you have / support.