I want to get the details of each condition result as true or false used in a join. For example below is the case
select emp.emp_id,emp.emp_name,hr.department,hr.salary
from employee emp left outer join HR
on emp.empId=HR.emp_id
and emp.emp_name=HR.emp_name
and emp.department=hr.department
and emp.salary=hr.salary;
now lets say first join condition emp_id is true and remaining are false. I want to get an output as
emp.emp_id,emp.emp_name,hr.department,hr.salary
true,false,false,false
and if first two conditions are true the output should be
true,true,false,false
and so on. Please ignore the database design here as it is taken just as an example. Thanks
Jafery
This might be along the lines of what you want to do here:
SELECT
CASE WHEN EXISTS (SELECT 1 FROM HR WHERE emp.empId = HR.empID)
THEN 'true' ELSE 'false' END AS emp_id,
CASE WHEN EXISTS (SELECT 1 FROM HR WHERE emp.emp_name = HR.emp_name)
THEN 'true' ELSE 'false' END AS emp_name,
CASE WHEN EXISTS (SELECT 1 FROM HR WHERE emp.department = HR.department)
THEN 'true' ELSE 'false' END AS department,
CASE WHEN EXISTS (SELECT 1 FROM HR WHERE emp.salary = HR.salary)
THEN 'true' ELSE 'false' END AS salary
FROM employee emp;
Each of the CASE with EXISTS statements probes, for record in the employee table, the HR table to see if it can find at least one matching record, for that particular column.
Note that this answer might not reflect an actual join, where a record in employee could potentially match multiple records in HR. But, in this case, it is not well defined what it would mean for a single column alone to match or not match.
Maybe you can try :
SELECT CASE WHEN emp.emp_id = HR.emp_id THEN 'True' ELSE 'False' as [emp_id],
CASE WHEN emp.emp_name = HR.emp_name THEN 'True' ELSE 'False' as [emp_name],
CASE WHEN emp.department = HR.department THEN 'True' ELSE 'False' as [department],
CASE WHEN emp.salary = HR.salary THEN 'True' ELSE 'False' as [salary],
from employee emp left outer join HR
on emp.empId=HR.emp_id
and emp.emp_name=HR.emp_name
and emp.department=hr.department
and emp.salary=hr.salary
Related
First, I need to unzip data from one table to transform into a new table. Secondly, I need to join another table to this new table based on customer id Z. Thirdly, I need to join yet another table to that second table using a different customer id, customer id Y.
Part 1: I have this data from Table A below.
NAME (Column 1)
VALUE (Column 2)
Customer_idZ (Coulmn 3)
account_status
ACTIVE
1234
card_template
Rewards
1234
customer_creation_date
1/8/2022
1234
enroll_store_code
pxweb
1234
enroll_store_name
Web Site
1234
push_opt_in
Yes
1234
I am transforming this data from Table A into a new table formatted as the below with this code
'''SELECT
Customer_idZ,
MAX(CASE WHEN Name = 'account_status' THEN VALUE END) AS account_status,
MAX(CASE WHEN Name = 'card_template' THEN VALUE END) AS card_template,
MAX(CASE WHEN Name = 'customer_creation_date' THEN VALUE END) AS customer_creation_date,
MAX(CASE WHEN Name = 'enroll_store_code' THEN VALUE END) AS enroll_store_code,
MAX(CASE WHEN Name = 'enroll_store_name' THEN VALUE END) AS enroll_store_name,
MAX(CASE WHEN Name = 'push_opt_in' THEN VALUE END) AS push_opt_in
FROM Table A
GROUP BY Customer_idZ;
Customer_idZ
account_status
card_template
customer_creation_date
enroll_store_code
enroll_store_name
push_opt_in
1234
ACTIVE
PX Rewards
1/8/2022
pxweb
Web Site
Yes
Part 2: I want to then join another table (Table B) to this this newly formatted data based on the shared customer_idZ field. The data in Table B is below;
Customer_idZ
Status
Customer_idY
1234
ACTIVE
567890
Part 3: I need to join another table (Table C) to Table B based on the shared Customer_idY field. The data in Table C is below;
Customer_idY
Household_size
Children_present_in_household
567890
6
Yes
Final: I need the final output solely to be a list of customer_idY and customer_idZ.
I am not sure how to structure the multi-join needed between the three tables and need to pull ids for those profiles that have active status' in table a and have household sizes of 4 or more
I just changed the column names in the query by #xQbert and hope it helps.
SELECT A.Customer_idZ
, B.Customer_idY
, account_status
, card_template
, customer_creation_date
, enroll_store_code
, enroll_store_name
, push_opt_in
, Household_size
, Children_present_in_household
FROM (SELECT
Customer_idZ,
MAX(CASE WHEN Name = 'account_status' THEN VALUE END) AS account_status,
MAX(CASE WHEN Name = 'card_template' THEN VALUE END) AS card_template,
MAX(CASE WHEN Name = 'customer_creation_date' THEN VALUE END) AS customer_creation_date,
MAX(CASE WHEN Name = 'enroll_store_code' THEN VALUE END) AS enroll_store_code,
MAX(CASE WHEN Name = 'enroll_store_name' THEN VALUE END) AS enroll_store_name,
MAX(CASE WHEN Name = 'push_opt_in' THEN VALUE END) AS push_opt_in
FROM A
GROUP BY Customer_idZ) A
INNER JOIN B
on A.Customer_idZ = B.Customer_idZ
INNER JOIN C
on B.Customer_idY = C.Customer_idY;
I'm ussing a common table expression (CTE) "NEWA" to reformat your "A" table... we could make this an inline view but I find a CTE easier to read
We may need to change INNER JOIN to LEFT OUTER JOIN depending on how you want to handle when related records are not in associated tables...
With NewA As (SELECT
Customer_idZ,
MAX(CASE WHEN Name = 'account_status' THEN VALUE END) AS account_status,
MAX(CASE WHEN Name = 'card_template' THEN VALUE END) AS card_template,
MAX(CASE WHEN Name = 'customer_creation_date' THEN VALUE END) AS customer_creation_date,
MAX(CASE WHEN Name = 'enroll_store_code' THEN VALUE END) AS enroll_store_code,
MAX(CASE WHEN Name = 'enroll_store_name' THEN VALUE END) AS enroll_store_name,
MAX(CASE WHEN Name = 'push_opt_in' THEN VALUE END) AS push_opt_in
FROM Table A
GROUP BY Customer_idZ)
SELECT Cusotmer_idZ
, Customer_idY
, account_status
, card_template
, customer_creation_date
, enroll_store_code
, enroll_store_name
, push_opt_in
, Household_size
, Children_present_in_household
FROM NewA A
INNER JOIN B
on A.Customer_idZ= B.Customer_idZ
INNER JOIN C
on B.Customer_IDY = C.Customer_IDY
WHERE Household_size >= 4
and account_status='Active'
We then use common join syntax to join on the relationships between the tables.
Now we could make these outer joins if you want all records from A and only those that match from B and all records from A combine b and those related records in C.
or we could use full outer joins to return all records from all tables. just depends on what you're after.
We could also use an inline view instead of a CTE:
SELECT A.Cusotmer_idZ
, B.Customer_idY
, account_status
, card_template
, customer_creation_date
, enroll_store_code
, enroll_store_name
, push_opt_in
, Household_size
, Children_present_in_household
FROM (SELECT
Customer_idZ,
MAX(CASE WHEN Name = 'account_status' THEN VALUE END) AS account_status,
MAX(CASE WHEN Name = 'card_template' THEN VALUE END) AS card_template,
MAX(CASE WHEN Name = 'customer_creation_date' THEN VALUE END) AS customer_creation_date,
MAX(CASE WHEN Name = 'enroll_store_code' THEN VALUE END) AS enroll_store_code,
MAX(CASE WHEN Name = 'enroll_store_name' THEN VALUE END) AS enroll_store_name,
MAX(CASE WHEN Name = 'push_opt_in' THEN VALUE END) AS push_opt_in
FROM Table A
GROUP BY Customer_idZ) A
INNER JOIN B
on A.Customer_idZ= B.Customer_idZ
INNER JOIN C
on B.Customer_IDY = C.Customer_IDY
WHERE Household_size >= 4
and account_status='Active'
here is what i would like to accomplish: I have two (or more) tables in join, and I would like to get a boolean output if some conditions are met, e.g.
Table1:
customer_id
customer_name
status
1
Google
waiting
2
Facebook
working
3
Salesforce
waiting
Table2:
customer_id
agent
outcome
1
John
failure
1
Mike
success
2
John
success
I would like to get for all customer ids true if status in Table1 is "waiting" and there is no Table2 record for that customer
Desired output:
customer_id
waiting_and_no_record_in_table_2
1
false
2
false
3
true
Any idea on how to reach this goal?
Thanks in advance
As there can be multiple rows per customer_id in table2, to achieve the desired result requires some simplification be applied on table2. For this I simply chose select distinct which is sufficient for the example, but alternatives do exist.
select
table1.customer_id
, case when table1.status = 'waiting' and t2.customer_id IS NULL then true else false end as waiting_and_no_record_in_table_2
from table1
left join (select distinct customer_id from table2) as t2 on table1.customer_id = t2.customer_id
order by
table1.customer_id
and alternative might be to join only successful rows from t2 although this may still produce more than one row per customer_id
select
table1.customer_id
, case when table1.status = 'waiting' and t2.customer_id IS NULL then true else false end as waiting_and_no_record_in_table_2
from table1
left join table2 as t2 on table1.customer_id = t2.customer_id
and t2.outcome = 'success'
order by
table1.customer_id
or these 2 might be combined to also ensure only one row per customer_id
select
table1.customer_id
, case when table1.status = 'waiting' and t2.customer_id IS NULL then true else false end as waiting_and_no_record_in_table_2
from table1
left join (select distinct customer_id from table2 where outcome = 'success') as t2 on table1.customer_id = t2.customer_id
order by
table1.customer_id
This is a hard problem to describe but I have Rails query where I join another table and I want to exclude any results where the join table contain one of three conditions.
I have a Device model that relates to a CarUserRole model/record. In that CarUserRole record it will contain one of three :role - "owner", "monitor", "driver". I want to return any results where there is no related CarUserRole record where role: "owner". How would I do that?
This was my first attempt -
Device.joins(:car_user_roles).where('car_user_roles.role = ? OR car_user_roles.role = ? AND car_user_roles.role != ?', 'monitor', 'driver', 'owner')
Here is the sql -
"SELECT \"cars\".* FROM \"cars\" INNER JOIN \"car_user_roles\" ON \"car_user_roles\".\"car_id\" = \"cars\".\"id\" WHERE (car_user_roles.role = 'monitor' OR car_user_roles.role = 'driver' AND car_user_roles.role != 'owner')"
Update
I should mention that a device sometimes has multiple CarUserRole records. A device can have an "owner" and a "driver" CarUserRole. I should also note that they can only have one owner.
Anwser
I ended up going with #Reub's solution via our chat -
where(CarUserRole.where("car_user_roles.car_id = cars.id").where(role: 'owner').exists.not)
Since the car_user_roles table can have multiple records with the same car_id, an inner join can result in the join table having multiple rows for each row in the cars table. So, for a car that has 3 records in the car_user_roles table (monitor, owner and driver), there will be 3 records in the join table (each record having a different role). Your query will filter out the row where the role is owner, but it will match the other two, resulting in that car being returned as a result of your query even though it has a record with role as 'owner'.
Lets first try to form an sql query for the result that you want. We can then convert this into a Rails query.
SELECT * FROM cars WHERE NOT EXISTS (SELECT id FROM car_user_roles WHERE role='owner' AND car_id = cars.id);
The above is sufficient if you want devices which do not have any car_user_role with role as 'owner'. But this can also give you devices which have no corresponding record in car_user_roles. If you want to ensure that the device has at least one record in car_user_roles, you can add the following to the above query.
AND EXISTS (SELECT id FROM car_user_roles WHERE role IN ('monitor', 'driver') AND car_id = cars.id);
Now, we need to convert this into a Rails query.
Device.where(
CarUserRole.where("car_user_roles.car_id = cars.id").where(role: 'owner').exists.not
).where(
CarUserRole.where("car_user_roles.car_id = cars.id").where(role: ['monitor', 'driver']).exists
).all
You could also try the following if your Rails version supports exists?:
Device.joins(:car_user_roles).exists?(role: ['monitor', 'driver']).exists?(role: 'owner').not.select('cars.*').distinct
Select the distinct cars
SELECT DISTINCT (cars.*) FROM cars
Use a LEFT JOIN to pull in the car_user_roles
LEFT JOIN car_user_roles ON cars.id = car_user_roles.car_id
Select only the cars that DO NOT contain an 'owner' car_user_role
WHERE NOT EXISTS(SELECT NULL FROM car_user_roles WHERE cars.id = car_user_roles.car_id AND car_user_roles.role = 'owner')
Select only the cars that DO contain either a 'driver' or 'monitor' car_user_role
AND (car_user_roles.role IN ('driver','monitor'))
Put it all together:
SELECT DISTINCT (cars.*) FROM cars LEFT JOIN car_user_roles ON cars.id = car_user_roles.car_id WHERE NOT EXISTS(SELECT NULL FROM car_user_roles WHERE cars.id = car_user_roles.car_id AND car_user_roles.role = 'owner') AND (car_user_roles.role IN ('driver','monitor'));
Edit:
Execute the query directly from Rails and return only the found object IDs
ActiveRecord::Base.connection.execute(sql).collect { |x| x['id'] }
I have this statement:
myuser.orders.exists?(['(orderstatus = ?) ', statusid])
It returns true since there is an orderstatus that matches the statusid.
Next I have:
myuser.orders.where('id not in (?)', nil).exists?(['(orderstatus = ?) ', statusid])
This returns false where I thought it might return true since there are no ids that are nil.
Then I have:
myuser.orders.where(nil).exists?(['(orderstatus = ?) ', statusid])
This returns true.
My question is why does the middle statement return false? It doesn't complain or throw any errors. I guess I'm using nil wrong, but can someone explain?
You're having trouble with SQL's NULL. The where in the middle one:
where('id not in (?)', nil)
becomes this SQL:
id not in (null)
and that's equivalent to this:
id != null
But the result of id != null is neither true nor false, the result is NULL and NULL in a boolean context is false; in fact, x = null and x != null result in NULL for all x (even when x itself is NULL); for example, in PostgreSQL:
=> select coalesce((11 = null)::text, '-NULL-');
coalesce
----------
-NULL-
(1 row)
=> select coalesce((11 != null)::text, '-NULL-');
coalesce
----------
-NULL-
(1 row)
=> select coalesce((null = null)::text, '-NULL-');
coalesce
----------
-NULL-
(1 row)
=> select coalesce((null != null)::text, '-NULL-');
coalesce
----------
-NULL-
(1 row)
MySQL and every other reasonably compliant database will do the same thing (with possibly different casting requirements to make the NULL obvious).
The result is that where(id not in (?)', nil) always yields an empty set and your existence check will always fail on an empty set.
If you want to say "all the rows where id is not NULL" then you want to say:
where('id is not null')
If your id is a primary key (as it almost certainly is), then id will never be NULL and you can leave that where out completely.
When you hand where just a nil:
where(nil)
where's argument parsing logic will ignore the nil completely and where(nil) will be the same as where() and where() does nothing at all to the query. The result is that the first and third queries are identical as far as the database is concerned.
I am using ruby 1.8.6 , rails 2.3.8.
Here , I have a problem with multiple combo box in Rails,
Product drop down list
Sku's drop down list ( depends on production selection )
Product tables fields are
id name
In Sku's tables fields are
id name product_id alias_id
Alias tables fields are
id name
For example I have Sku's tables data like below
id name product_id alias_id
1. 100-m 1 10
2. 10-ml 1 NULL
3. 150 1 2
4. 200-m 1 10
5. 300-m 1 10
in Controller I written query like,
#skus = Sku.all(:conditions => ["product_id = ? ",
params[:id]],:select=>"skus.id,
CASE when skus.alias_id IS NOT NULL then (SELECT alias.name FROM alias WHERE
alias.id = skus.alias_id group by alias.name) END AS 'skus_name'",
:order=>"skus_name" ,:include=>[:alias])
This query written output like,
id skus_name
1. 100gms
2. 10-ml
3. 150-ml
4. 100gms
5. 100gms
Can any one help me how to get the distinct results?
Thanks in advance
You can either call uniq on the #sku variable that is returned.
#skus = Sku.all(:conditions => ["product_id = ? ",
params[:id]],:select=>"skus.id,
CASE when skus.alias_id IS NOT NULL then (SELECT alias.name FROM alias WHERE
alias.id = skus.alias_id group by alias.name) END AS 'skus_name'",
:order=>"skus_name" ,:include=>[:alias]).uniq
This will perform the same DB select but get unique results in ruby.
The alternative is to use DISTINCT in the select
#skus = Sku.all(:conditions => ["product_id = ? ",
params[:id]],:select=>"skus.id,
CASE when skus.alias_id IS NOT NULL then (SELECT DISTINCT alias.name FROM alias WHERE
alias.id = skus.alias_id group by alias.name) END AS 'skus_name'",
:order=>"skus_name" ,:include=>[:alias])
This will only get unique results in the database.
I'd go with the second option as it should be quicker than doing uniq in ruby :)