How to write Flexible Search for joined tables in Hybris - mysql

I am trying to get all users which don't have addresses, there is a relation between user and address tables(one to many) and the address has an owner attribute that refers to Users pk. how can I achieve that ??
SELECT {u:pk}
FROM {User AS u
LEFT JOIN Address AS a ON {u:pk}={a:owner}}
WHERE {u:owner} IS NULL
I wrote a query which I guess doesn't work correctly

You can try something like this :
SELECT {pk} FROM {User} WHERE {pk} not in ({{ SELECT {owner} FROM {Address} WHERE {owner} IS NOT NULL }})

Related

Outer query value is not able use in inner query

SELECT
(select Email from Contact where AccountId = Account.Id),
Id,
BillingCity,
BillingCountry,
BillingPostalCode,
BillingState,
BillingStreet,
Name,
Phone
FROM Account
where
LastModifiedDate < #[flowVars['timestamp']]
Problem here is I am not able to get the Email which is present in the sub query based on the Id of current iteration. Can you please help on this
I'm not sure how you are running the query, and how you are accessing the result, but if you are doing it in a place that does not give you the result dynamically, meaning that you try to access the columns by expected name, i.e. trying to get the "email" column somehow, then you need to fix a small issue in the query.
You need to add the AS operator to give your subquery a meaningful name like email like so:
...
(select Email from Contact where AccountId = Account.Id) as email,
...
See fiddle here for working example: db-fiddle
You can get rid of the scalar sub-query and just put a join to the CONTACT table instead. The following assumes that the CONTACT table is an optional relationship.
SELECT
con.email,
acct.Id,
acct.BillingCity,
acct.BillingCountry,
acct.BillingPostalCode,
acct.BillingState,
acct.BillingStreet,
acct.Name,
acct.Phone
FROM account acct
LEFT OUTER JOIN
contact con ON con.account_id = acct.account_id
WHERE acct.LastModifiedDate < #[flowVars['timestamp']]

Create a WHERE OR IN postgres

Right now I have the query
DELETE FROM connections
WHERE "user_b_id" IN
(SELECT "id"
FROM "users"
WHERE 'dharness.student#gmail.com'="email")
But what I really want is
WHERE "user_b_id" OR "user_a_id" IN ...
But I can't figure out how to make that work. Is there an operator for this?
If users.email is unique you can write
WHERE (SELECT id FROM users
WHERE email = 'dharness.student#gmail.com')
IN (user_b_id , user_a_id)

SQL Joining the correct username

Say I have the following tables
User
__________
id
username
email
FriendGame
__________
id
useroneid
usertwoid
status
I want to get games that the current user is part of, so I do this:
SELECT *
FROM FriendGame
WHERE useroneid=1663702020516206
OR usertwoid=1663702020516206
AND STATUS =1;
This is fine. Now I want to join the username, but only for the user that ISNT the supplied user (1663702020516206) since in FriendGame the given user exists EITHER as useroneid or usertwoid.
You can pretty much translate your logic directly into an on clause:
SELECT fg.*
FROM FriendGame fg JOIN
User u
ON (fg.useroneid = 1663702020516206 and fg.usertwoid = u.id) or
(fg.usertwoid = 1663702020516206 and fg.useroneid = u.id)
WHERE 1663702020516206 in (fg.useroneid, fg.usertwoid) AND
STATUS = 1;
Actually, the where clause is not necessary to get the right result set, but I think it makes the intention of the query clearer.

Sql Result IN a Query

dont blame for the database design.I am not its database architect. I am the one who has to use it in current situation
I hope this will be understandable.
I have 3 tables containing following data with no foreign key relationship b/w them:
groups
groupId groupName
1 Admin
2 Editor
3 Subscriber
preveleges
groupId roles
1 1,2
2 2,3
3 1
roles
roleId roleTitle
1 add
2 edit
Query:
SELECT roles
from groups
LEFT JOIN preveleges ON (groups.groupId=preveleges.groupId)
returns specific result i.e roles.
Problem: I wanted to show roleTitle instead of roles in the above query.
I am confused how to relate table roles with this query and returns required result
I know it is feasible with coding but i want in SQL.Any suggestion will be appreciated.
SELECT g.groupName,
GROUP_CONCAT(r.roleTitle
ORDER BY FIND_IN_SET(r.roleId, p.roles))
AS RoleTitles
FROM groups AS g
LEFT JOIN preveleges AS p
ON g.groupId = p.groupId
LEFT JOIN roles AS r
ON FIND_IN_SET(r.roleId, p.roles)
GROUP BY g.groupName ;
Tested at: SQL-FIDDLE
I would change the data structure it self. Since It's not normalised, there are multiple elements in a single column.
But it is possible with SQL, if for some (valid) reason you can't change the DB.
A simple "static" solution:
SELECT REPLACE(REPLACE(roles, '1', 'add'), '2', 'edit') from groups
LEFT JOIN preveleges ON(groups.groupId=preveleges.groupId)
A more complex but still ugly solution:
CREATE FUNCTION ReplaceRoleIDWithName (#StringIds VARCHAR(50))
RETURNS VARCHAR(50)
AS
BEGIN
DECLARE #RoleNames VARCHAR(50)
SET #RoleNames = #StringIds
SELECT #RoleNames = REPLACE(#RoleNames, CAST(RoleId AS VARCHAR(50)), roleTitle)
FROM roles
RETURN #RoleNames
END
And then use the function in the query
SELECT ReplaceRoleIDWithName(roles) from groups
LEFT JOIN preveleges ON(groups.groupId=preveleges.groupId)
It is possible without function, but this is more readable. Made without editor so it's not tested in anyway.
You also tagged the question with PostgreSQL and it's actually quite easy with Postgres to work around this broken design:
SELECT grp.groupname, r.roletitle
FROM groups grp
join (
select groupid, cast(regexp_split_to_table(roles, ',') as integer) as role_id
from privileges
) as privs on privs.groupid = grp.groupid
join roles r on r.roleid = privs.role_id;
SQLFiddle: http://sqlfiddle.com/#!12/5e87b/1
(Note that I changed the incorrectly spelled name preveleges to the correct spelling privileges)
But you should really, really re-design your data model!
Fixing your design also enables you to define foreign key constraints and validate the input. In your current model, the application would probably break (just as my query would), if someone inserted the value 'one,two,three' into the roles table.
Edit
To complete the picture, using Postgres's array handling the above could be slightly simplified using a similar approach as MySQL's find_in_set()
select grp.groupname, r.roletitle
from groups grp
join privileges privs on grp.groupid = privs.groupid
join roles r on r.roleid::text = any (string_to_array(privs.roles, ','))
In both cases if all role titles should be shown as a comma separated list, the string_agg() function could be used (which is equivalent to MySQL's group_concat()
select grp.groupname, string_agg(r.roletitle, ',')
from groups grp
join privileges privs on grp.groupid = privs.groupid
join roles r on r.roleid::text = any (string_to_array(privs.roles, ','))
group by grp.groupname

(mysql) how to add wildcard on where condition when joining with another table?

i have one query that need some changes, and i don't get any clue to do this :
this is my query :
select * from user_data a
left join user_group b
on (a.role like b.role)
actually role value in userdata is (varchar)'staff'
and role value in group is (varchar)'staff;security;finance'
so i don't get result what i expected ..
i imagine the query should be similar to this :
select * from user_data a
left join user_group b
on (b.role like a.role+";%") // using wildcard
and i still don't know the right query using wildcard to this case
any one can help?
You can use CONCAT:
select * from user_data a
left join user_group b
on (b.role like CONCAT(a.role,";%")) // using wildcard
Note - does b.role only have to match a.role at the beginning? what if it was security;staff;finance? You could do CONCAT('%',a.role,'%').
You could do CONCAT('%','a.role','%') to handle matching a.role at any position, but only if you can be sure that you won't have nested roles.
For example: if b.role is staff and a.role is finance;gardenstaff;security, then this row will be returned from the query even though the role is gardenstaff and not staff.
As an alternative, you can use RLIKE instead of LIKE. This is basically a regular-expressions verson of LIKE.
In particular, the regex [[:<:]]staff[[:>:]] will match the whole word staff. The [[:<:]] and [[:>:]] stand for word boundaries, which stop you from matching the staff in gardenstaff.
So, your query could be:
select * from user_data a
left join user_group b
on (b.role RLIKE CONCAT('[[:<:]]',a.role,'[[:>:]]'))
And this would work for b.role being anywhere in the semicolon-separated a.role.