Issues with the OR clause - tsql

I am having some trouble with the OR clause.
I am trying to join two large tables and given below is a sample data from the tables
Table1 (t1)
vendor addr1 city zip
ADT PO BOX 371956 PITSBURGH 15250
Table2 (t2)
vendor addr1 city zip
ADT PO Box 371956 Pittsburgh 15250-7956
The first two select statements given below display one row of data from the two tables.
In the third select, I have an OR clause and this does not display any rows.
The OR clause should not affect the result set.
select *
from t1
left join t2
on t1.addr1 = t2.addr1
select *
from t1
left join t2
on t1.addr1 = t2.addr1
and (t1.city = t2.city)
the select below does not display any data. WHY?
select *
from t1
left join t2
on t1.addr1 = t2.addr1
and ((t1.city = t2.city) or (t1.zip = t2.zip))

On your last query you have:
t1.addr1 = t2.addr2 AND
(
t1.city = t2.city OR
t1.zip = t2.zip
)
Considering your sample data:
t1."PO BOX 371956" = t2."PO Box 371956" AND -- TRUE
(
t1."PITSBURGH" = t2."Pittsburgh" OR -- FALSE
t1."15250" = t2."15250-7956" -- FALSE
)
You got:
= TRUE AND (FALSE OR FALSE)
= TRUE AND FALSE
= FALSE
So, no soup for you.

Related

Find a difference between 2 tables

I want to check that the poi_equipement table (relationship table) corresponds to the data in the data table (i.e. a two-way check)
https://dbfiddle.uk/gFMjbIpX
detect that wc (in poi_equipement) is extra (because it is not present in the data table) and that hotel is not in poi_equipement so it is absent compared to the data table
I don't understand why with the raquĂȘte except he just answers me hotel.
I want him to answer me hotel and wc.
select object from data where subject = 'url1'
except
select subject from poi_equipement inner join equipement on poi_equipement.equipement_id = equipement.id;
ideally I want to know when I have a difference in poi_equipement, in data or in the 2 tables
A full outer join will do
with params as (
select 'url1' as subject),
data_object as (
select d.object
from data d
join params prm
on d.subject = prm.subject),
equipment_subject as (
select e.subject
from poi_equipement pe
join poi p
on pe.poi_id = p.id
join equipement e
on pe.equipement_id = e.id
join params prm
on p.id_url = prm.subject)
select d.object as data,
e.subject as poi_equipment
from data_object d
full outer
join equipment_subject e
on d.object = e.subject
where d.object is null
or e.subject is null;
Result:
data |poi_equipment|
-----+-------------+
hotel| |
|wc |
You can remove where clause if you need to see which item is in both places.

How can I use value from main select in Left Outer Join select - T-SQL

In my below T-SQL Query I need to use EFP_MessageCenter.MessageSender from my main SELECT in the SELECT in my LEFT OUTER JOIN as the value where I have placed <MessageSenderInitials>.
When I set (EFP_MessageCenter_1.MessageSender = EFP_MessageCenter.MessageSender) or (EFP_MessageCenter_1.MessageSender = MessageSenderInitials) I get the error The multi-part identifier "EFP_MessageCenter.MessageSender" could not be bound.
How can I get this to work?
SELECT LOWER(EFP_MessageCenter.MessageSender) AS MessageSenderInitials
, MAX(SenderInfo.FullName) AS SenderFullName
, MAX(SenderInfo.ProfilePicture) AS SenderProfilePicture
, MAX(EFP_MessageCenter_Receiver.UserID) AS ReceiverID
, MAX(EFP_MessageCenter.MessageTimestamp) AS ChangeDate
, COUNT(DisplayCountSelect.Displayed) AS CountNonReadMessages
FROM EFP_MessageCenter_Receiver
INNER JOIN EFP_MessageCenter ON EFP_MessageCenter_Receiver.MessageID = EFP_MessageCenter.id
INNER JOIN EFP_EmploymentUser AS SenderInfo ON EFP_MessageCenter.MessageSender = SenderInfo.Initials
LEFT OUTER JOIN
(SELECT EFP_MessageCenter_Receiver_1.Displayed, EFP_MessageCenter_Receiver_1.UserID, EFP_MessageCenter_1.MessageSender
FROM EFP_MessageCenter AS EFP_MessageCenter_1
INNER JOIN EFP_MessageCenter_Receiver AS EFP_MessageCenter_Receiver_1 ON EFP_MessageCenter_1.id = EFP_MessageCenter_Receiver_1.MessageID
WHERE (EFP_MessageCenter_Receiver_1.Displayed = 0) AND (EFP_MessageCenter_Receiver_1.UserID = 65) AND (EFP_MessageCenter_1.MessageSender = '<MessageSenderInitials>'))
AS DisplayCountSelect
ON DisplayCountSelect.UserID = EFP_MessageCenter_Receiver.UserID
WHERE (EFP_MessageCenter_Receiver.UserID = 65) AND (EFP_MessageCenter.MessageType = 'SPECIFIC')
GROUP BY EFP_MessageCenter.MessageSender
ORDER BY ChangeDate DESC
I've made a slight refactor of your query and changed the outer join to an an outer apply
It's not going to be 100% working I'm sure but should allow you to tweak it and include the correlation you need to.
I suspect you could move the CountNonReadMessages to a count(*) in the apply and possibly remove the aggregation, but that's just a guess.
select Lower(mc.MessageSender) as MessageSenderInitials
, Max(s.FullName) as SenderFullName
, Max(s.ProfilePicture) as SenderProfilePicture
, Max(mr.UserID) as ReceiverID
, Max(mc.MessageTimestamp) as ChangeDate
, Count(s.Displayed) as CountNonReadMessages
from EFP_MessageCenter_Receiver mr
join EFP_MessageCenter mc on mr.MessageID = mc.id
join EFP_EmploymentUser eu on mc.MessageSender = eu.Initials
outer apply (
select mr.Displayed
from EFP_MessageCenter mcx
join EFP_MessageCenter_Receiver mrx on mcx.id = mrx.MessageID
where mrx.Displayed = 0
and mrx.UserId=mr.UserId
and mcx.UserID = 65 /* this should probably be correlated */
and mcx.MessageSender = '<MessageSenderInitials>'
) s
where mr.UserID = 65 and mc.MessageType = 'SPECIFIC'
group by mc.MessageSender
order by ChangeDate desc

Recursive CTE ancestry (Employee with multiple Managers)

I am having difficulties trying to output all managers above an employee. The employees table does not have a manager_id column, which makes this a bit complicated.
The hierarchy is defined in a references table.
Each employee belongs to a department and is assigned a position. A position with level 1 is a manager, level 0 is non-manager.
To get the manager of a manager, we take the parent_id of the current department and look for an employee assigned with a position with level 1.
The function I currently have only returns the employee's direct manager (from the non-recursive term).
CREATE OR REPLACE FUNCTION public.get_employee_managers(employees_row employees)
RETURNS SETOF employees
LANGUAGE sql
STABLE
AS $function$
WITH RECURSIVE managers AS (
SELECT e1.*
FROM
employees e1
JOIN "references" AS employees_row_department ON employees_row_department.id = employees_row.department_id
JOIN "references" AS e1_department ON e1_department.id = e1.department_id
JOIN "references" AS e1_position ON e1_position.id = e1.position_id
WHERE
e1_department.id = employees_row_department.parent_id AND e1_position.level = 1 AND e1.active = 1 AND e1.is_deleted = false
OR
e1_department.id = employees_row.department_id AND e1_position.level = 1 AND e1.active = 1 AND e1.is_deleted = false AND e1.id <> employees_row.id
UNION
SELECT m1.*
FROM
managers m1
JOIN "references" AS m1_department ON m1_department.id = m1.department_id
JOIN "references" AS m1_position ON m1_position.id = m1.position_id
INNER JOIN employees AS e2 ON (m1_department.parent_id = e2.department_id AND m1_position.level = 1 AND e2.active = 1 AND e2.is_deleted = false)
)
SELECT * FROM managers ORDER BY department_id ASC
$function$
Using the following recursive term gives me the same result as the one above
SELECT e2.*
FROM
employees e2
JOIN "references" AS e2_department ON e2_department.id = e2.department_id
JOIN "references" AS e2_position ON e2_position.id = e2.position_id
INNER JOIN managers m1 ON m1.id = e2.id
JOIN "references" AS m1_department ON m1_department.id = m1.department_id
WHERE
e2_department.id = m1_department.parent_id AND e2_position.level = 1 AND e2.active = 1 AND e2.is_deleted = false
Changing the second recursive term seems to give me the result I was looking for.
INNER JOIN managers m1 ON m1.id = e2.id
to
INNER JOIN managers m1 ON m1.id <> e2.id

Postgres get rows which hasnt match in other table

I need your help. I need an advanced Query to my database. Im showing part of my database following:
Place (id, name, address)
Local (id, place_id, name)
PlaceReservation(id, local_id, date)
Media_Place (id, place_id, type)
Now I need a query, which gets all places with logo, which have AT LEAST ONE local which hasn't been reserved on a specific day e.g: 2015-07-01.
Help me please, because I haven't an idea how to do it. I thought about an outer join but I don't know how use it.
I was trying by:
$query = 'SELECT DISTINC *,
(SELECT sum(po.rating)/count(po.id)
FROM "Place_Opinion" po
WHERE po.place_id = p.id AND po.deleted = false) AS rating,
mp.path as logo_path
FROM "Place" p
INNER JOIN "Media_Place" mp ON mp.place_id = p.id
JOIN Local ON Local.place_id = Place.id
LEFT JOIN (
SELECT id AS rr, local_id
FROM PlaceReservation
WHERE date_start = \'2015-07-01\') Reserved ON Reserved.local_id = Local.id
WHERE mp.type = ' . Model_Row_MediaPlace::LOGO_TYPE . '
AND mp.deleted = false
AND p.deleted = false
AND rr IS NULL';
Looking for things that do not exist in a database is usually very inefficient. But you can change the logic around by finding places that do have a booking for the specified date, then LEFT JOIN that to all places with a logo and filter out the records with a reservation:
SELECT DISTINCT p.*, po.rating, mp.path as logo_path
FROM "Place" p
JOIN "Media_Place" mp ON mp.place_id = p.id AND mp.deleted = false AND mp.type = ?
JOIN Local ON Local.place_id = p.id
LEFT JOIN (
SELECT id AS rr, local_id
FROM PlaceReservation
WHERE date_start = '2015-07-01') reserved ON reserved.local_id = Local.id
LEFT JOIN (
SELECT place_id, avg(rating) AS rating
FROM "Place_Opinion"
WHERE deleted = false
GROUP BY place_id) po ON po.place_id = p.id
WHERE p.deleted = false
AND reserved.rr IS NULL;
The average rating per places is calculated in a separate sub-query. The error you had was because you referenced the "Place" table (p.id) before it was defined. For simple columns you can do that, but for sub-queries you can't.

PostgreSQL Same Table Left Outer Join With Multiple Tables

I have a table which needs to left outer joined with two different tables. When I put the table twice in the query and join it with it self in the where clause (like the sentence below) it works. I think this should not be the correct way. How can I write the select statement and outer join the table with multiple different tables?
SELECT cols."COLUMN_NAME"
, COALESCE(translations."COLUMN_LANG_TITLE",cols."COLUMN_TITLE") AS "COLUMN_TITLE"
, options."OPTION_DESC"
FROM
"EXTAPP_SETUP"."OBJECT_COLUMNS_TAB" cols LEFT OUTER JOIN "EXTAPP_SETUP"."COLUMN_LANG_TITLES_TAB" translations
ON translations."EXTAPP_ID" = cols."EXTAPP_ID" and translations."OBJECT_NAME" = cols."OBJECT_NAME" and translations."COLUMN_NAME" = cols."COLUMN_NAME" and translations."LANGUAGE_CODE" = 'fr',
"EXTAPP_SETUP"."OBJECT_COLUMNS_TAB" cols2 LEFT OUTER JOIN "EXTAPP_SETUP"."COL_FIX_OPTIONS_TAB" options
ON options."EXTAPP_ID" = cols2."EXTAPP_ID" and options."OBJECT_NAME" = cols2."OBJECT_NAME" and options."COLUMN_NAME" = cols2."COLUMN_NAME"
WHERE cols."EXTAPP_ID" = cols2."EXTAPP_ID" and cols."OBJECT_NAME" = cols2."OBJECT_NAME" and cols."COLUMN_NAME" = cols2."COLUMN_NAME"
You can use subsequent left joins.
Since you are not realy using your cols2 table, you can eliminate it from the query. This would also eliminate the where clause, because you don't need to join the cols table with itself
SELECT cols."COLUMN_NAME"
, COALESCE(translations."COLUMN_LANG_TITLE",cols."COLUMN_TITLE") AS "COLUMN_TITLE"
, options."OPTION_DESC"
FROM "EXTAPP_SETUP"."OBJECT_COLUMNS_TAB" cols
LEFT OUTER JOIN "EXTAPP_SETUP"."COLUMN_LANG_TITLES_TAB" translations
ON translations."EXTAPP_ID" = cols."EXTAPP_ID"
and translations."OBJECT_NAME" = cols."OBJECT_NAME"
and translations."COLUMN_NAME" = cols."COLUMN_NAME"
and translations."LANGUAGE_CODE" = 'fr'
LEFT OUTER JOIN "EXTAPP_SETUP"."COL_FIX_OPTIONS_TAB" options
ON options."EXTAPP_ID" = cols."EXTAPP_ID"
and options."OBJECT_NAME" = cols."OBJECT_NAME"
and options."COLUMN_NAME" = cols."COLUMN_NAME"