Identify table data is retrieved from - tsql

I have a typical question with a twist.
I need to modify the following T SQL query. Currently it only looks in one table for information. I need to look into two tables with identical columns for information. One table contains current employees and one contains former employees
SELECT t.net_Id
,e.fname
,e.lname
FROM tblTrackingEmployee t
join view_employee e
on e.net_id = t.net_id
where trackingid = #trackingId
and empType = #empType
What I was thinking of doing is using a union to look in both. An employee will either appear in one table or the other, it will never be in both.
SELECT t.net_Id
,e.fname
,e.lname
FROM tblTrackingEmployee t
JOIN view_employee e
ON e.net_id = t.net_id
WHERE trackingid = #trackingId
AND empType = #empType
union
SELECT t.net_Id
,fe.fname
,fe.lname
FROM tblTrackingEmployee t
JOIN view_employee fe
ON fe.net_id = t.net_id
WHERE trackingid = #trackingId
AND empType = #empType
However here is the twist, I need to know if the person/s returned are current or former employees. Is there a way to add a column to the returned table that has a 1 if its a current employee or 0 if its a former employee? Each trackingId can potentially contain both types of employees.

Add a constant column to each SELECT clause - you can alias it:
SELECT t.net_Id
,e.fname
,e.lname
,'Current' AS Type
FROM tblTrackingEmployee t
JOIN view_employee e
ON e.net_id = t.net_id
WHERE trackingid = #trackingId
AND empType = #empType
union
SELECT t.net_Id
,fe.fname
,fe.lname
,'Former'
FROM tblTrackingEmployee t
JOIN view_formerEmployee fe
ON fe.net_id = t.net_id
WHERE trackingid = #trackingId
AND empType = #empType

Let me get this straight, you have two tables, one has current employees one has former employees? This was a bad idea already you could have had one table with a status ('Active' / 'Inactive'). In any event just add a field, like an int, that you want to each query
SELECT
0 AS TheField,
....
FROM
Table
UNION ALL
SELECT
1 AS TheField,
...
FROM
table

You can also sort by the Status if you would like:
SELECT U.* FROM
(
SELECT t.net_Id AS ID
,e.fname AS FName
,e.lname AS LName
,'Current' AS EmployStatus
FROM tblTrackingEmployee t
JOIN view_employee e
ON e.net_id = t.net_id
WHERE trackingid = #trackingId
AND empType = #empType
union
SELECT t.net_Id AS ID
,fe.fname AS FName
,fe.lname AS LName
,'Former' AS EmployStatus
FROM tblTrackingEmployee t
JOIN view_formerEmployee fe
ON fe.net_id = t.net_id
WHERE trackingid = #trackingId
AND empType = #empType
) AS U
ORDER BY U.EmployStatus

Related

Trying to . convert a value to a name during output

the values returned in column a.user_id are id numbers. I would like to return them as a name or initials e.g. 1 = Chris O or C.ONeill
I have tried CASE function but did not know where to put it
SELECT DISTINCT
sb.start_time::date AS shift_date,
i.title AS industry,
wl.name AS venue_name,
w.first_name,
w.last_name,
MIN(cs.start_time::date) AS first_completed_shift,
i.title AS industry,
w.interviewed_on AS induction_date,
d.issue_date AS edbs_issue_date,
d.created_at AS date_dbs_added,
a.user_id --IS IT POSSIBLE TO GET THESE AS VALUES,e.g. a.user_id '1' = 'Chris O or C.ONeill' USING USER NAMES INSTEAD OF USER ID?
FROM shift_bookings sb
JOIN jobs j ON sb.job_id = j.id
JOIN listings l ON j.listing_id = l.id
JOIN work_locations wl ON l.venue_id = wl.id
JOIN workers w ON sb.worker_id = w.id
JOIN completed_shifts cs ON w.id = cs.worker_id
JOIN documents d ON w.id = d.documentable_id
JOIN audits a ON d.id = a.auditable_id
JOIN industries i ON j.industry_id = i.id
WHERE sb.shift_id IN (253106)
AND d.document_type_id = 33
AND a.auditable_type = 'Document'
GROUP BY
sb.start_time::date,
wl.name,
w.first_name,
w.last_name,
i.title,
w.interviewed_on,
d.issue_date,
d.created_at,
a.user_id
a.user_id output will be something else I can set

Problems with Postgresql ERROR: subquery uses ungrouped column "ev.title" from outer query

I have a query like this:
select c.id, c.name, c.website, c.longdescription, c.description, c.email,
(SELECT jsonb_agg(ev) FROM
(SELECT ev.title, ev.description, ev.longdescription,
(SELECT jsonb_agg(ed) FROM
(SELECT ed.startdate, ed.enddate, ed.id WHERE ed.id notnull)ed) as dates, ev.id WHERE ev.id notnull) ev) as events,
(SELECT jsonb_agg(ca) FROM (SELECT ct.zip, ca.id, ca.street1, ca.street2, ca.addresstype_id, ST_Y(ca.geopoint::geometry) as latitude, ST_X(ca.geopoint::geometry) as longitude
WHERE ca.id notnull)ca) as addresses
FROM companies c
LEFT JOIN events ev ON ev.company_id = c.id
LEFT JOIN companyaddresses ca ON ca.company_id = c.id
LEFT JOIN cities ct ON ct.id = ca.city_id
LEFT JOIN eventdates ed ON ed.event_id = ev.id
GROUP by c.id
I am getting the error "ERROR: subquery uses ungrouped column "ev.title" from
outer query Position: 125".
Can't figure out how to group it correctly for the subqueries. Any suggestions?
Give this a try:
SELECT c.id, c.name, c.website, c.longdescription, c.description, c.email,
    (SELECT jsonb_agg(ev) FROM
        (SELECT even.title, even.description, even.longdescription,
            (SELECT jsonb_agg(ed) FROM
                (SELECT eventdates.startdate, eventdates.enddate, eventdates.id FROM eventdates WHERE eventdates.event_id = even.id)ed) as dates,
        even.id FROM events even WHERE even.company_id = c.id) ev) as events,
jsonb_agg((SELECT ca FROM (SELECT ct.zip, ca.id, ca.street1, ca.street2, ca.addresstype_id, ST_Y(ca.geopoint::geometry) as latitude, ST_X(ca.geopoint::geometry) as longitude WHERE ca.id notnull)ca)) as addresses
FROM companies c
LEFT JOIN companyaddresses ca ON ca.company_id = c.id
LEFT JOIN cities ct ON ct.id = ca.city_id
Group by c.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.

TSQL efficiency - INNER JOIN replaced by EXISTS

Can the following be rewritten to be more efficient?
I would use EXISTS if I didn't need fields from country but I do need those fields, and am not sure how to write this to make it more efficient.
SELECT distinct
p.ProvinceID,
p.Abbv as RegionCode,
p.name as RegionName,
cn.Code as CountryCode,
cn.Name as CountryName
FROM dbo.provinces AS p
INNER JOIN dbo.Countries AS cn ON p.CountryID = cn.CountryID
INNER JOIN dbo.Cities c on c.ProvinceID = p.ProvinceID
INNER JOIN dbo.Listings AS l ON l.CityID = c.CityID
WHERE l.IsActive = 1 AND l.IsApproved = 1
There are two things to note:
You're joining to dbo.Listings which results in many records, so you need to use DISTINCT (usually an expensive operator)
For any tables with columns not in the select you can move into an EXISTS (but the query planner effectively does this for you anyway)
So try this:
SELECT
p.ProvinceID,
p.Abbv as RegionCode,
p.name as RegionName,
cn.Code as CountryCode,
cn.Name as CountryName
FROM dbo.provinces AS p
INNER JOIN
dbo.Countries AS cn
ON p.CountryID = cn.CountryID
WHERE EXISTS (SELECT 1 FROM
dbo.Listings l
INNER JOIN dbo.Cities c
on l.CityID = c.CityID
WHERE c.ProvinceID = p.ProvinceID
AND l.IsActive = 1 AND l.IsApproved = 1
)
Check the query plans before and after - the query planner might be smart enough to do this anyway, but you have removed your distinct
The following will often perform even better by providing the optimizer more useful information:
SELECT
p.ProvinceID,
p.Abbv as RegionCode,
p.name as RegionName,
cn.Code as CountryCode,
cn.Name as CountryName
FROM dbo.provinces AS p
INNER JOIN
dbo.Countries AS cn
ON p.CountryID = cn.CountryID
INNER JOIN (
SELECT
p.ProvinceID
FROM
dbo.Listings l
INNER JOIN dbo.Cities c
on l.CityID = c.CityID
WHERE l.IsActive = 1 AND l.IsApproved = 1
GROUP BY
p.ProvinceID
) list
on list.ProvinceID = p.ProvinceID

Aggregate similar row

Suppose I've a table like this:
NAME REF1 REF2 DRCT
A (null) Ra D1
A Rb (null) D1
A (null) Rc D2
B Rd (null) D3
B (null) Re D3
I want aggregate this table in something like:
NAME REF1 REF2 DRCT
A Rb Ra D1
A (null) Rc D2
B Rd Re D3
As you can see, i want aggregate each row with same name. I've search through COALESCE and various aggregate functions but I haven't found what i was looking for. Any idea?
Assuming that what I ask in my previous comment is true, (only null or a given value for REF1 and REF2 for each NAME, DRCT pair), this seems to work:
select NAME, M_REF1, M_REF2, DRCT
from (
select A.NAME, coalesce(A.REF1, B.REF1) m_REF1,
coalesce(A.REF2, B.REF2) m_REF2, A.REF1 A_REF1, B.REF1 B_REF1,
A.REF2 A_REF2, B.REF2 B_REF2, A.DRCT
from Table1 A JOIN Table1 B on A.NAME = B.NAME AND A.DRCT = B.DRCT)
WHERE A_REF1 = m_REF1 AND B_REF2 = m_REF2
UNION
select A.NAME, A.REF1, A.REF2, A.DRCT
FROM Table1 A JOIN
(select NAME, DRCT, COUNT(*)
from Table1
group by NAME, DRCT
HAVING COUNT(*) = 1) B ON A.NAME = B.NAME AND A.DRCT = B.DRCT;
The union is used because the rows with only one record are not included in the first SELECT.
But this is somewhat simpler, and works too:
select A.NAME, coalesce(A.REF1, B.REF1) M_REF1, coalesce(A.REF2,B.REF2) M_REF2,A.DRCT
from Table1 A LEFT OUTER JOIN Table1 B ON A.DRCT = B.DRCT AND A.NAME = B.NAME
WHERE NVL2(A.REF1,0,1) = 1 AND NVL2(B.REF1,0,1) =0
AND NVL2(A.REF2,0,1) = 0 AND NVL2(B.REF2,0,1) = 1
UNION
select A.NAME, A.REF1, A.REF2, A.DRCT
FROM Table1 A JOIN
(select NAME, DRCT, COUNT(*)
from Table1
group by NAME, DRCT
HAVING COUNT(*) = 1) B ON A.NAME = B.NAME AND A.DRCT = B.DRCT;