Nesting Queries to get multiple column results - sql

Have two queries , one collects moves in based on property and unit type the other would collect based on Move Outs for the same data. when ran separately they yield the correct information (move outs are 6 and move ins are 11) Have tried nesting in select and from statements but not getting what i need. When nested within the select am getting the correct move outs per unit type, but each line for move ins is total move ins. I recall that the nesting here would only return one value but know there is a way to return the value for each row. Any assistance is appreciated.
SELECT
p.scode as PropNumber,
p.saddr1 propname,
ut.scode as UnitType,
COUNT(t.hmyperson) as Moveouts,
(
SELECT COUNT(t.hmyperson) as MoveIns
FROM
tenant t
JOIN unit u ON t.hunit = u.hmy
JOIN property p ON p.hmy = u.hproperty
JOIN unittype ut ON ut.hmy = u.HUNITTYPE
WHERE
t.dtmovein >= getdate() - 14
AND p.scode IN ('gsaff')
) mi
FROM
Property p
JOIN unit u ON u.hproperty = p.hmy
JOIN tenant t ON t.hunit = u.hmy
JOIN unittype ut ON ut.hmy = u.HUNITTYPE
WHERE
p.scode IN ('gsaff')
AND t.DTMOVEOUT >= getdate()- 14
GROUP BY
ut.scode,
p.scode,
p.saddr1
With this data is coming out like :
PropNumber Propname UnitType MoveOuts MoveIns
1 x tc2 1 11
1 x tc3 2 11
1 x tc4 1 11
1 x tc5 1 11
1 x tc6 1 11 <pre>
Move in column should display as
2
5
1
0
3

You need to correlate the subquery according to the record being processed in the outer query. This also requires that you use different table aliases in the subquery than in the outer query.
It is hard to tell without seeing sample data, however I would expect that you need to correlate with all non-aggregated columns in the outer query.
Try changing :
(
SELECT COUNT(t.hmyperson) as MoveIns
FROM
tenant t
JOIN unit u ON t.hunit = u.hmy
JOIN property p ON p.hmy = u.hproperty
JOIN unittype ut ON ut.hmy = u.HUNITTYPE
WHERE
t.dtmovein >= getdate() - 14
AND p.scode IN ('gsaff')
) mi
To :
(
SELECT COUNT(t.hmyperson) as MoveIns
FROM
tenant t1
JOIN unit u1 ON t1.hunit = u1.hmy
JOIN property p1 ON p1.hmy = u1.hproperty
JOIN unittype ut1 ON ut1.hmy = u1.HUNITTYPE
WHERE
t1.dtmovein >= getdate() - 14
AND p1.scode IN ('gsaff')
AND p1.scode = p.scode
AND p1.saddr1 = p.saddr1
AND ut1.scode = ut.scode
) mi

Related

SQL Count condition in main Query

I want to pick on those who for the column is_initial_event: the values can be 0 or 1. I only want those who have only 1. Not that they have both 1 and 0. There are multiple detail rows for is_initial_event.
select ac.Full_name, pe.program_start_date, pe.program_end_date, tp.approved_by_Description as
Approved, ev.is_initial_event, tp.staff from all_clients_view ac
inner join program_enrollment_expanded_view pe
on ac.people_id = pe.people_id
inner join service_plan_goals_objectives_methods_view tp
on ac.people_id = tp.people_id
inner join service_plan_event_view ev
on ac.people_id = ev.people_id
where pe.program_name = 'CFTSS' and tp.Approved_by_description is null
Here I tried to add in the count, what I want to count is that if the people_id has > 0 for ev.Is_initial_event = 1 and also has > when ev.IS_initial_event = 0, then I don't want that people_id only when it only has records where ev.is_initial_event = 1 not both.
Are you looking for window functions?
select *
from (
select
ac.Full_name,
pe.program_start_date,
pe.program_end_date,
tp.approved_by_Description as Approved,
ev.is_initial_event,
tp.staff,
min(ev.is_initial_event) over(partition by ac.people_id) min_initial_event
from all_clients_view ac
inner join program_enrollment_expanded_view pe
on ac.people_id = pe.people_id
inner join service_plan_goals_objectives_methods_view tp
on ac.people_id = tp.people_id
inner join service_plan_event_view ev
on ac.people_id = ev.people_id
where
pe.program_name = 'CFTSS'
and tp.Approved_by_description is null
) t
where min_initial_event = 1
This returns rows for which all rows having the same people_id have initial_event set to 1 (note that this assumes that this column contains only 0s and 1s, as explained in your question).

Return only results that match more than 2 conditions

How do I only return results if more than two values from a list are found?
For example, if they don't have at least three of the following codes attached to their account then don't include them:
I13.0
I13.2
I20.0
I20.1
I20.8
I20.9
I21.01
I21.02
I21.09
I21.11
I21.19
I21.21
I21.29
I21.3
I21.4
I21.9
I21.A1
I21.A9
I22.0
Do I just need to put having count(distinct PROB.ICD10DiagnosisCode) > 2 after the group statement? I am getting results but I want to make sure I am not taking the long way around the bus.
SELECT DISTINCT
PER.ID AS PatientID,
IORG.OrganizationMRN AS PatientMRN
FROM works..Problem PROB (nolock)
JOIN works..Problem_Encounter PROBENC ON PROB.ID = PROBENC.ProblemID
JOIN works..Encounter ENC ON PROBENC.EncounterID = ENC.ID
JOIN works..patient_member PM ON ENC.PatientID = PM.ID
JOIN works..Document ON Document.EncounterID = ENC.ID
JOIN works..DocumentEvent
ON Document.documentid = DocumentEvent.documentid
JOIN works..Person PER ON Document.PatientID = PER.ID
JOIN works..Patient_Iorg IORG
ON PER.ID = IORG.PersonID and IORG.InternalOrganization = 3
WHERE PROB.ProblemStatusDE IN (9)
AND PROB.RecordedDTTM > DATEADD(month,-6,GETDATE())
AND PROB.ICD10DiagnosisCode IN
(
SELECT ICD10DiagnosisCode
FROM CVCReports.dbo.rptPETEligibleICD10
)
AND PM.IsDeceasedFLAG = 'N'
AND DocumentEvent.documenteventde NOT IN (18)
AND Document.Status LIKE 'Final%'
AND Document.DocumentTypeDE NOT IN (288)
AND ENC.DTTM > DATEADD(year,-2,GETDATE())
GROUP BY OrganizationMrn, PER.ID
having count(distinct PROB.ICD10DiagnosisCode) > 2

altering query in db2 to fix count from a join

I'm getting an aggregated count of records for orders and I'm getting the expected count on this basic query:
SELECT
count(*) as sales_180,
180/count(*) as velocity
FROM custgroup g
WHERE g.cstnoc = 10617
AND g.framec = 4847
AND g.covr1c = 1763
AND g.colr1c = 29
AND date(substr(g.extd1d,1,4)||'-'||substr(g.EXTD1d,5,2)||'-'||substr(g.EXTD1d,7,2) ) between current_Date - 180 DAY AND current_Date
But as soon as I add back in my joins and joined values then my count goes from 1 (which it should be) to over 200. All I need from these joins is the customer ID and the manager number. so even if my count is high, I'm basically just trying to say "for this cstnoc, give me the slsupr and xlsno"
How can I perform this below query without affecting the count? I only want my count (sales_180 and velocity) coming from the custgroup table based on my where clause, but I then just want one value of the xcstno and xslsno based on the cstnoc.
SELECT
count(*) as sales_180,
180/count(*) as velocity,
c.xslsno as CustID,
cr.slsupr as Manager
FROM custgroup g
inner join customers c
on g.cstnoc = c.xcstno
inner join managers cr
on c.xslsno = cr.xslsno
WHERE g.cstnoc = 10617
AND g.framec = 4847
AND g.covr1c = 1763
AND g.colr1c = 29
AND date(substr(g.extd1d,1,4)||'-'||substr(g.EXTD1d,5,2)||'-'||substr(g.EXTD1d,7,2) ) between current_Date - 180 DAY AND current_Date
GROUP BY c.xslsno, cr.slsupr
You are producing multiple rows when joining, so your count is now counting all the resulting rows with all that [unintended] multiplicity.
The solution? Use a table expression to pre-compute your count, and then you can join it to the other tables, as in:
select
g2.sales_180,
g2.velocity,
c.xslsno as CustID,
cr.slsupr as Manager
from customers c
join managers cr on c.xslsno = cr.xslsno
join ( -- here the Table Expression starts
SELECT
count(*) as sales_180,
180/count(*) as velocity
FROM custgroup g
WHERE g.cstnoc = 10617
AND g.framec = 4847
AND g.covr1c = 1763
AND g.colr1c = 29
AND date(substr(g.extd1d,1,4)||'-'||substr(g.EXTD1d,5,2)
||'-'||substr(g.EXTD1d,7,2) )
between current_Date - 180 DAY AND current_Date
) g2 on g2.cstnoc = c.xcstno
You can also use a Common Table Expression (CTE) that will produce the same result:
with g2 as (
SELECT
count(*) as sales_180,
180/count(*) as velocity
FROM custgroup g
WHERE g.cstnoc = 10617
AND g.framec = 4847
AND g.covr1c = 1763
AND g.colr1c = 29
AND date(substr(g.extd1d,1,4)||'-'||substr(g.EXTD1d,5,2)
||'-'||substr(g.EXTD1d,7,2) )
between current_Date - 180 DAY AND current_Date
)
select
g2.sales_180,
g2.velocity,
c.xslsno as CustID,
cr.slsupr as Manager
from customers c
join managers cr on c.xslsno = cr.xslsno
join g2 on g2.cstnoc = c.xcstno

How to use alias of a subquery to get the running total?

I have a UNION of 3 tables for calculating some balance and I need to get the running SUM of that balance but I can't use PARTITION OVER, because I must do it with a sql query that can work in Access.
My problem is that I cannot use JOIN on an alias subquery, it won't work.
How can I use alias in a JOIN to get the running total?
Or any other way to get the SUM that is not with PARTITION OVER, because it does not exist in Access.
This is my code so far:
SELECT korisnik_id, imePrezime, datum, Dug, Pot, (Dug - Pot) AS Balance
FROM (
SELECT korisnik_id, k.imePrezime, r.datum, SUM(IIF(u.jedinstven = 1, r.cena, k.kvadratura * r.cena)) AS Dug, '0' AS Pot
FROM Racun r
INNER JOIN Usluge u ON r.usluga_id = u.ID
INNER JOIN Korisnik k ON r.korisnik_id = k.ID
WHERE korisnik_id = 1
AND r.zgrada_id = 1
AND r.mesec = 1
AND r.godina = 2017
GROUP BY korisnik_id, k.imePrezime, r.datum
UNION ALL
SELECT korisnik_id, k.imePrezime, rp.datum, SUM(IIF(u.jedinstven = 1, rp.cena, k.kvadratura * rp.cena)) AS Dug, '0' AS Pot
FROM RacunP rp
INNER JOIN Usluge u ON rp.usluga_id = u.ID
INNER JOIN Korisnik k ON rp.korisnik_id = k.ID
WHERE korisnik_id = 1
AND rp.zgrada_id = 1
AND rp.mesec = 1
AND rp.godina = 2017
GROUP BY korisnik_id, k.imePrezime, rp.datum
UNION ALL
SELECT uu.korisnik_id, k.imePrezime, uu.datum, '0' AS Dug, SUM(uu.iznos) AS Pot
FROM UnosUplata uu
INNER JOIN Korisnik k ON uu.korisnik_id = k.ID
WHERE korisnik_id = 1
GROUP BY uu.korisnik_id, k.imePrezime, uu.datum
) AS a
ORDER BY korisnik_id
You can save a query (let's name it Query1) for the UNION of the 3 tables and then create another query that returns each row in the first query and calculates the sum of the rows that are before it (optionally checking that they are in the same group).
It should be something like this:
SELECT *, (
SELECT SUM(Value) FROM Query1 AS b
WHERE b.GroupNumber=a.GroupNumber
AND b.Position<=a.Position
) AS RunningSum
FROM Query1 AS a
However, it's more efficient to do that in the report.

SELF-JOIN discarding true CROSS JOIN rows

I have the following query;
What I get is tickets information. I use self-join to obtain the requester and the assignee in the same row:
SELECT z.id AS TICKET, z.name AS Subject, reqs.name AS Requester, techs.name AS Assignee,
e.name AS Entity,DATE_FORMAT(tt.date,'%y%-%m%-%d') AS DATE,
DATE_FORMAT(tt.date,'%T') AS HOUR,
CASE WHEN z.priority = 6 THEN 'Mayor' WHEN z.priority = 5 THEN 'Muy urgente' WHEN z.priority = 4 THEN 'Urgente'WHEN z.priority = 3 THEN 'Mediana' WHEN z.priority = 2 THEN 'Baja' WHEN z.priority =1 THEN 'Muy baja' END AS Priority,
c.name AS Category, i.name AS Department
FROM glpi_tickets_users tureq
JOIN glpi_tickets_users tutech ON tureq.tickets_id = tutech.tickets_id
JOIN glpi_users AS reqs ON tureq.users_id = reqs.id
JOIN glpi_users AS techs ON tutech.users_id = techs.id
JOIN glpi_tickets z ON z.id = tureq.tickets_id
LEFT OUTER JOIN glpi_tickettasks tt ON z.id = tt.tickets_id
LEFT JOIN glpi_itilcategories i ON z.itilcategories_id = i.id
LEFT JOIN glpi_usercategories c ON c.id = reqs.usercategories_id
INNER JOIN glpi_entities e ON z.entities_id = e.id
WHERE (tureq.id < tutech.id AND tureq.type < tutech.type) OR
(tureq.id < tutech.id AND tureq.users_id = tutech.users_id) OR
(tureq.id = tutech.id AND tureq.users_id = tutech.users_id)
The problem is that I get something like that:
1 Report jdoe jdoe Development 16-06-07 11:56:17 Mediana Software Mkt
1 Report jdoe fwilson Development 16-06-07 11:56:17 Mediana Software MKt
1 Report fwilson fwilson Development 16-06-07 11:56:17 Mediana Software Mkt
2 Task11 gwilliams gwilliams Ops 16-06-08 12:00:00 ALTA Hardware Def
3 Task12 gwilliams gwilliams Ops 16-06-08 12:01:00 ALTA Hardware Def
I don't want first and third row because is a CROSS JOIN result. Second row is OK, because jdoe is a requester and fwilson an assignee.
The problem is that sometimes requester and assignee are the same, eg: he creates a ticket for a task that himself will do. For example, 4th and 5th rows are OK.
So, how should I do to make a difference for those distinct cases, i.e.: I need to include:
tureq.id = tech.id AND req.users_id = tech.users.id
BUT NOT IF ALREADY EXISTS
tureq.id = tech.id AND req.users_id <> tech.users_id
Update
The main problem is that a user can assign to himself a ticket:
SELECT * from glpi_tickets_users WHERE type = 2 GROUP BY tickets_id HAVING COUNT(users_id)<2 limit 3;
+----+------------+----------+------+------------------+-------------------+
| id | tickets_id | users_id | type | use_notification | alternative_email |
+----+------------+----------+------+------------------+-------------------+
| 1 | 2 | 12 | 2 | 1 | NULL |
| 3 | 6 | 13 | 2 | 1 | NULL |
| 7 | 8 | 14 | 2 | 1 | NULL |
+----+------------+----------+------+------------------+-------------------+
Update 2:
It was a human mistake. The problem was really not about self-assigned tickets. Rather it was either that some tickets had not Requester or had Requester but still had not any resolver assigned.
I've found
As there are always the two types per ticket you are interested in, you can simply select the according records, so as to get requester and assignee per ticket.
select
t.id as ticket,
t.name as subject,
requester.name as requester,
assignee.name as assignee,
e.name as entity,
date_format(tt.date,'%y%-%m%-%d') as date,
date_format(tt.date,'%T') as hour,
case t.priority
when 6 then 'Mayor'
when 5 then 'Muy urgente'
when 4 then 'Urgente'
when 3 then 'Mediana'
when 2 then 'Baja'
when 1 then 'Muy baja'
end as priority,
uc.name as category,
ic.name as department
from glpi_tickets t
join glpi_entities e on e.id = t.entities_id
join
(
select tu.tickets_id, u.name, u.usercategories_id
from glpi_tickets_users tu
join glpi_users u on u.id = users_id
where tu.type = 1
) requester on requester.tickets_id = t.id
join
(
select tu.tickets_id, u.name
from glpi_tickets_users tu
join glpi_users u on u.id = users_id
where tu.type = 2
) assignee on assignee.tickets_id = t.id
left join glpi_itilcategories ic on ic.id = t.itilcategories_id
left join glpi_usercategories uc on uc.id = requester.usercategories_id;
left outer join glpi_tickettasks tt on tt.tickets_id = t.id
The only thing I wonder is: There can be several ticket tasks per ticket. So what do you want to do then? Have one line per ticket task in your results? This is what the query does. Only, it looks queer that your result rows don't contain any information on the tasks except for the dates, so you may have many, many lines with the same data, only with different dates. So maybe, you'd rather want the first or last date per ticket. To get the last date per ticket, you'd replace the last line in the query with:
left outer join
(
select tickets_id, max(date) as date
from glpi_tickettasks
group by tickets_id
) tt on tt.tickets_id = t.id
And you probably want to add an ORDER BY clause.
you need to add more qualifiers to your joins for example
JOIN glpi_tickets_users tutech ON tureq.tickets_id = tutech.tickets_id and tutech.type = 2