I am having trouble using a LEFT OUTER JOIN with Rails. I think I have my Ruby code down but when I enter it into the rails console I get one result and when I copy the produced MySQL I get another result. An entire column (value) is missing in the rails console. Why is it that the SQL is the exact same but I am getting different results? Ideally, I want the results to include the value column. As always any help would be greatly appreciated.
Rails Console Response
2.0.0-p353 :023 > SecurityItem.joins("LEFT OUTER JOIN security_role_permissions ON security_role_permissions.security_item_id = security_items.id AND security_role_permissions.role_id ='1'").select("security_items.name, security_role_permissions.value")
SecurityItem Load (0.7ms) SELECT security_items.name, security_role_permissions.value FROM `security_items` LEFT OUTER JOIN security_role_permissions ON security_role_permissions.security_item_id = security_items.id AND security_role_permissions.role_id ='1
=> #<ActiveRecord::Relation
[#<SecurityItem id: nil, key: "ChangePassword", name: "Change Password">,
#<SecurityItem id: nil, key: "AddUsers", name: "Add Users">,
#<SecurityItem id: nil, key: "UpdateUsers", name: "Update Users">,
#<SecurityItem id: nil, key: "DeleteUsers", name: "Delete Users">]>
MySQL Response
mysql> SELECT security_items.name, security_role_permissions.value FROM `security_items` LEFT OUTER JOIN security_role_permissions ON security_role_permissions.security_item_id = security_items.id AND security_role_permissions.role_id ='1';
+-----------------+-------+
| name | value |
+-----------------+-------+
| Change Password | 1 |
| Add Users | NULL |
| Update Users | NULL |
| Delete Users | NULL |
+-----------------+-------+
Only the attributes from the SecurityItem class appear in the return result. However, you can access the attributes from the joined table through the 'attributes' method.
security_items = SecurityItem.joins("LEFT OUTER JOIN security_role_permissions
ON security_role_permissions.key = security_items.key AND
security_role_permissions.role_id ='1'").select("security_items.name,
security_items.key, security_role_permissions.permission")
security_items.each { |security_item| puts security_item.attributes['permission'] }
Related
I have been unable to query objects based on a property in an array of objects.
I am trying to query all orders that have the event with id 7:
const orders = await this.orderRepository.find({where: {events: {elemMatch: {'id': event.id}}}});
The above gives me the following error:
ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''{\"id\":\"7\"}
If i try the following filter, I always get an empty array back:
{where: {events: {like: '%id%'}}}
What is the correct approach for Loopback 4?
UPDATE:
I am using MySQL 8.0.
This is the definition of events in my order model:
#property({
type: 'array',
itemType: 'object',
required: false,
})
events: CartItem[] | null;
Solution
Since you are using the MySQL loopback connector to connect to your MySQL database, currently this connector treats both String/JSON as VARCHAR. As such, you could try the following modification to like
{where: {events: {like: '%id:'+7+'%'}}}
or
const orders = await this.orderRepository.find({
where: {
events: {
like: '%id:'+event.id+'%'
}
}
});
or using regular expressions
const orders = await this.orderRepository.find({
where: {
events: {
regexp: '.*id:'+event.id+'.*'
}
}
});
const orders = await this.orderRepository.find({
where: {
events: {
regexp: new RegExp(".*id:"+event.id+".*")
}
}
});
in an attempt to match the json pattern {id:7,name:'Event 7'} where in this case the value inside id could be 7.
Assumptions
Based on your question and the mysql error shown, the following assumptions were made:
Schema (MySQL v5.7)
create table samples(id int primary key auto_increment, events varchar(400));
insert into samples(events) values
('[{id:3,name:\"Boscobel\"},{id:4,name:\"Rays\"}]'),
('[{id:7,name:\"Boscobel 7\"},{id:8,name:\"Rays 8\"}]');
Should Receive Results
Query #1
select * from samples where events like '%id\:7%';
| id | events |
| --- | ----------------------------------------------- |
| 2 | [{id:7,name:"Boscobel 7"},{id:8,name:"Rays 8"}] |
Query #2
select * from samples where events like '%id:7%';
| id | events |
| --- | ----------------------------------------------- |
| 2 | [{id:7,name:"Boscobel 7"},{id:8,name:"Rays 8"}] |
Should Not Receive Results
Query #3
select * from samples where events like '%id\:70%';
There are no results to be displayed.
Query #4
select * from samples where events like '%id:200%';
There are no results to be displayed.
View on DB Fiddle
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.
I like to fetch some products from the Database with a custom command in akeneo.
I'm using the ProductRepositoryInterface
public function read()
{
return $this->repository->findBy(
[
'enabled' => true,
'family' => ['projector', 'projector_child', 'projector_parent'],
]
);
}
And this is the generated query:
SELECT t0.id AS id1, t0.is_enabled AS is_enabled2, t0.created AS created3, t0.updated AS updated4, t0.family_id AS family_id5 FROM pim_catalog_product t0 WHERE t0.is_enabled = ? AND t0.family_id IN (?)
As you can see in the Statement, the family is threaded as an Id. But I want to search by the family code.
What I have to change?
In the Pim/Component/Catalog/Model/AbstractProduct is an attribute for the family and familyId. So there have to be a way to query for the family code.
Maybe it's relevant, but this is an Akeneo 1.6 installation.
So first, to query products in Akeneo, you should use the Product Query Builder (PQB). If you're using the 1.6, here is the link to the documentation to use it, it's pretty straightforward: https://docs.akeneo.com/1.6/cookbook/catalog/product/query.html
To have an exhaustive list of the filters on attributes & fields that can be used with the PQB, you can use the php app/console pim:product:query-help command on your PIM.
As you noticed, the family is not an attribute but a field, you'll find it in the field filters of the command above:
php app/console pim:product:query-help
Useable field filters...
+-----------------+--------------------------------+-----------------------------------------------------------+
| field | operators | filter_class |
+-----------------+--------------------------------+-----------------------------------------------------------+
| family | IN, NOT IN, EMPTY, NOT EMPTY | Pim\Bundle\CatalogBundle\Doctrine\ORM\Filter\FamilyFilter |
| family.id | IN, NOT IN, EMPTY, NOT EMPTY | Pim\Bundle\CatalogBundle\Doctrine\ORM\Filter\FamilyFilter |
| family.code | IN, NOT IN, EMPTY, NOT EMPTY | Pim\Bundle\CatalogBundle\Doctrine\ORM\Filter\FamilyFilter |
+-----------------+--------------------------------+-----------------------------------------------------------+
You can see now that you can search on the family.code field.
For your example, you'll end up with something like this:
<?php
// Get a new instance of the PQB
$pqbFactory = $this->getContainer()->get('pim_catalog.query.product_query_builder_factory');
$pqb = $pqbFactory->create([
'default_locale' => 'en_US',
'default_scope' => 'ecommerce'
]);
// Now you can search for products with your family codes
$pqb->addFilter(
'family.code',
'IN',
['projector', 'projector_child', 'projector_parent']
);
// Retrieve your products
$productsCursor = $pqb->execute();
foreach ($productsCursor as $product) {
// your custom logic
}
I run this code in python 3.6 (pythonanywhere.com) using MySQL
import MySQLdb
conn = MySQLdb.connect('username.mysql.pythonanywhere-services.com', 'username', 'password', 'username$to_do')
c = conn.cursor()
c.execute('SELECT task FROM list')
rows = c.fetchall()
list_em = []
number = 0
for eatchRow in rows:
list_em.append(eatchRow)
print("nr %s: %s" % (number, list_em[number]))
number += 1
del1 = int(input("Chose the number of the list item you want to delete: "))
delstatmt = "DELETE FROM list WHERE task = ?"
print (list_em[del1])
#c.execute(delstatmt, (list_em[del1],))
I am creating a list called "list_em" and fill with the content from the column "task" in the table "list". I would like "print (list_em[del1])" to return 'Gå med hunden' -A clean string that I can use to run the last script that is commented out. Instead get something that looks like this with brackets and a comma(from console):
nr 0: ('Skura Trappan',)
nr 1: ('Gå med hunden.',)
Chose the number of the list item you want to delete: 1
('Gå med hunden.',)
OBS! The table does not have any ID, just two columns:
mysql> select * from list;
+-----------------+-------------+
| task | status |
+-----------------+-------------+
| Skura Trappan | Not started |
| Gå med hunden. | Not started |
+-----------------+-------------+
2 rows in set (0.00 sec)
What you're getting back from the MySQL library is a list of tuples, one for each row returned by the query. The elements of each tuple are the values of the columns you're querying for.
In this case, you're querying for one column, so each element of the list is a one-element tuple, which Python will represent as (value,) -- which is what you're seeing.
So in order to print out just the value from the tuple, you need to extract it, just like you would with a list:
for eatchRow in rows:
list_em.append(eatchRow[0])
print("nr %s: %s" % (number, list_em[number]))
number += 1
I'm using Sinatra and the mysql2 gem.
I'm trying to do a simple update of a field called "process_complete", which is a boolean.
My code is:
user = User.first!(email: user_email)
user.update(:process_complete => true)
I get the error:
19:30:05 web.1 | INFO - (0.000603s) SELECT * FROM `users` WHERE (`email` = 'user#email.com') LIMIT 1
19:30:05 web.1 | 2015-10-18 19:30:05 - Sequel::MassAssignmentRestriction - method process_complete= doesn't exist:
Am I doing something wrong here? When I look up SELECT * FROMusersWHERE (email= 'user#email.com') LIMIT 1 in mysql I see my user, and "process_complete" is set as 0.
What am I doing wrong here?
Try the following:
user = User.where(email: user_email).first
user.process_complete = true
user.save