Query limit number of output records with relation - sql

I am trying to make a query which returns different records, but I find myself with a problem regarding the relationship since it brings me the number of records that have that relationship, for example I have a Father event with several locations, there are two tables " events" and "events_localities", in the events table is the id of the event with which the locations associated with that event are related, when doing the query it brings me, for example, if I have 2 locations for that event, it brings me 2 records with the same idEvento, but I need it to bring me only 1, I've been trying the query for a long time but it doesn't work, thank you very much.
this is the query:
SELECT DISTINCT ev.id as idEvento,
cat.nemonico as tipoEvento,
ev.fecha_registro as ocurrencia,
ev.estado as estado,
ev.alto_impacto as altoImpacto,
ev.calificacion as calificacion,
ev.es_macroevento as esMacroevento,
evloc.tipo_localidad as tipolocalidad,
evloc.id_localidad as idLocalidad,
pa.codigo as codigoParroquia,
pa.nombre as nombreParroquia,
ca.nombre as nombreCanton,
pr.nombre as nombreProvincia
FROM tbl_evento_peligroso ev
JOIN tbl_evento_peligroso_localidad evloc
ON ev.id = evloc.id_evento_peligroso
JOIN cat_enumerado cat
ON ev.enum_tipo_evento = cat.id
JOIN tbl_parroquia pa
ON pa.id = evloc.id_localidad
JOIN tbl_canton ca
ON ca.id = pa.id_canton
JOIN tbl_provincia pr
ON pr.id = ca.id_provincia
WHERE ev.fecha_registro
BETWEEN '2023-01-24 00:00:00'
AND '2023-02-11 23:59:59'
AND evloc.estado = 'A'
AND evloc.tipo_localidad = 'PA';

Related

Why do I have multiple entries per entity in the query output?

Would like to know why my query displays multiple entries per entity in the output.
From what I understand there is only one active policy per entity.
Created query with SQL Server Management Studio, my output to display correctly has parameters, and I have tried the following with my query.
Currently my SQL SSMS query output displays the following:
Entity_Number Building_Name PolicyID Description Start_Date End_Date
400 Xpress 4 5 Day Grace 7/1/2019 9/27/2019
400 Xpress 18 2 Day Grace 7/3/2018 7/13/2018
400 Xpress 19 4 Day Grace 2/27/2019 2/27/2019
What I really would like to know is how do I drill down and find out why my query returns multiples?
[Query]
SELECT
e.Entity_Number,
bld.Building_Name,
cbp.PolicyId,
cbp.Description,
cbp.StartDate,
cbp.EndDate
FROM
dbo.buildings AS bld
INNER JOIN dbo.entities AS e
ON bld.Entity_ID = e.Entity_ID
INNER JOIN Collections.Building AS cbp
ON bld.Building_ID = cb.BuildingId
INNER JOIN Collections.BuildingProfile AS cbpro
ON cbp.BuildingPolicyId = cbpro.BuildingPolicyId
WHERE
bld.Building_Active = 1
AND e.Active = 1
Use the "salami technique" to isolate where the unexpected rows come from. What I mean by this is that you cut down the query like a salami by omitting each join (and any column references related to that join) one by one.
e.g. start with masking the join to Collections.BuildingProfile:
SELECT
e.Entity_Number
, bld.Building_Name
, cbp.PolicyId
, cbp.Description
, cbp.StartDate
, cbp.EndDate
FROM dbo.buildings AS bld
INNER JOIN dbo.entities AS e ON bld.Entity_ID = e.Entity_ID
INNER JOIN Collections.Building AS cbp ON bld.Building_ID = cbp.BuildingId
-- INNER JOIN Collections.BuildingProfile AS cbpro ON cbp.BuildingPolicyId = cbpro.BuildingPolicyId
WHERE bld.Building_Active = 1
AND e.Active = 1
Does this remove the unexpected columns? If not then try:
SELECT
e.Entity_Number
, bld.Building_Name
--, cbp.PolicyId
--, cbp.Description
--, cbp.StartDate
--, cbp.EndDate
FROM dbo.buildings AS bld
INNER JOIN dbo.entities AS e ON bld.Entity_ID = e.Entity_ID
--INNER JOIN Collections.Building AS cbp ON bld.Building_ID = cbp.BuildingId
--INNER JOIN Collections.BuildingProfile AS cbpro ON cbp.BuildingPolicyId = cbpro.BuildingPolicyId
WHERE bld.Building_Active = 1
AND e.Active = 1
Eventually by masking out each join (and any related column references to that table) you will discover which table is producing the unexpected multiplication of rows.
Once that table is identified I suggest you reconsider all assumptions you have made about how that table had been joined. For example, you state that " From what I understand there is only one active policy per entity." Is that really true?
Once you know where the problem starts, and you reconsider how that data should actually be used within the query, you should be closer to a solution. e.g. perhaps you need more conditions in the join, or you need to join a subquery instead of directly to the table.
Note:
Collections.BuildingProfile does not seem needed by the query, why not omit it
anyway?
reformatting for "comma first" in the select clause helps simplify use of the "salami technique"

sql counting the number is not working correctly

I make related queries and the counting does not work correctly, when I connect 4 and join and add a condition, it does not count correctly, but without the 4th joina and the condition it works correctly. first option result = 2
SELECT
pxixolog_details.*,
directions.direction,
COUNT(directions.direction) procent
FROM
pxixolog_details
LEFT JOIN psixologs_direction ON pxixolog_details.id = psixologs_direction.psixolog_id
LEFT JOIN directions ON directions.id = psixologs_direction.direction_id
LEFT JOIN psixologs_weeks ON pxixolog_details.id = psixologs_weeks.psixolog_id
WHERE
directions.direction IN(
'Трудности в отношениях',
'Проблемы со сном',
'Нежелательная агрессия'
)
AND birthday BETWEEN '1956-04-29' AND '2021-04-29' AND psixologs_weeks.week = '4'
GROUP BY
pxixolog_details.id
and the second one doesn't work correctly. result = 4
SELECT
pxixolog_details.*,
directions.direction,
COUNT(directions.direction) procent
FROM
pxixolog_details
LEFT JOIN psixologs_direction ON pxixolog_details.id = psixologs_direction.psixolog_id
LEFT JOIN directions ON directions.id = psixologs_direction.direction_id
LEFT JOIN psixologs_weeks ON pxixolog_details.id = psixologs_weeks.psixolog_id
LEFT JOIN psixologs_times ON pxixolog_details.id = psixologs_times.psixolog_id
WHERE
directions.direction IN(
'Трудности в отношениях',
'Проблемы со сном',
'Нежелательная агрессия'
)
AND birthday BETWEEN '1956-04-29' AND '2021-04-29' AND psixologs_weeks.week = '4'
AND (psixologs_times.time = '09:00' OR psixologs_times.time = '10:00')
GROUP BY
pxixolog_details.id
what am I doing wrong?
You get double the amount of results when doing 4 JOINs because through the new (4th) JOIN you allow 2 records (9:00 and 10:00 o'clock) for each of the other joined records in the first 3 JOINs. That can lead to the observed result.
Check your data and make sure that your 4th JOIN condition yields a 1:1 record matching with the other data.
The last table has psixologs_times matches multiple rows for each psixolog_id.
You can easily see this using a query:
select psixolog_id, count(*)
from psixologs_times
group by psixolog_id
having count(*) > 1;
How you fix this problem depends on what you want to do. The simplest solution is to use count(distinct):
COUNT(DISTINCT directions.direction) as procent
However, this might just be hiding the problem. You might want to choose one row from the psixologs_times table. Or pre-aggregate it. Or do something else.

MS Access Query to get unique rows based on a single column

I have a query as:
SELECT MAX(SubmissionLog.ID), AccountTypes.Description,
AccountContacts.FirstName, AccountContacts.LastName, Accounts.Name,
Accounts.StreetAddress, Accounts.MailAddress,SubmissionLog.EffectiveDate,
SubmissionLog.ExpirationDate, StatusCodes.Description
FROM
AccountContacts RIGHT JOIN (StatusReasons
RIGHT JOIN ([JILL_MG utah sub query]
RIGHT JOIN (StatusCodes
RIGHT JOIN (Carriers
RIGHT JOIN (AgencyLocations
RIGHT JOIN (Brokers
RIGHT JOIN (Agencies
RIGHT JOIN (SubmissionLog
LEFT JOIN (AccountTypes
RIGHT JOIN (BusinessTypes
RIGHT JOIN Accounts ON BusinessTypes.ID = Accounts.BusinessTypeID)
ON AccountTypes.ID = Accounts.AccountTypeID)
ON SubmissionLog.AccountID = Accounts.ID)
ON Agencies.ID = SubmissionLog.AgencyID)
ON Brokers.ID = SubmissionLog.BrokerID)
ON (AgencyLocations.LocationID = Brokers.AgencyLocationID) AND
(AgencyLocations.AgencyID = Brokers.AgencyID))
ON Carriers.ID = SubmissionLog.WinningCarrierID)
ON StatusCodes.ID = SubmissionLog.StatusID)
ON [JILL_MG utah sub query].SubLogID = SubmissionLog.ID)
ON StatusReasons.StatusReasonID = SubmissionLog.StatusReasonID)
ON AccountContacts.AccountID = Accounts.ID
WHERE ( (AccountTypes.Description) Like "prospect" Or (AccountTypes.Description) Like "prev*")
AND ( (SubmissionLog.EffectiveDate)>#12/31/2010#)
AND ((StatusCodes.Description) Like "not*")
AND ((Accounts.dbType_id) In (15)) )
GROUP BY AccountTypes.Description, AccountContacts.FirstName,
AccountContacts.LastName, Accounts.Name, Accounts.StreetAddress,
Accounts.MailAddress,SubmissionLog.EffectiveDate,
SubmissionLog.ExpirationDate, StatusCodes.Description
ORDER BY Accounts.Name
It gives submission details based on Account Names. But we can have Account names repeated as we can have many submissions for an Account with different Effective Dates. But here i need to modify thr query so that I can get Account details with he most recent Effective date(having greatest value of SubmissionLog.Id) irrespective of unique combinations of Account Name with other columns. I jus want Account name with the recent effective date so that there is only one row per Account Name. I have used MAX(SubmissionLog.Id) to filter but due to unique combinations with other columns the Account Name is getting repeated as it has more than one combination with different values with other columns. Any workaround on this guys..??
What you need is a subquery that takes the data from these three tables:
SELECT MAX(SubmissionLog.ID) MaxId, Accounts.Name
FROM
SubmissionLog
LEFT JOIN (AccountTypes
RIGHT JOIN (BusinessTypes
RIGHT JOIN Accounts ON BusinessTypes.ID = Accounts.BusinessTypeID)
ON AccountTypes.ID = Accounts.AccountTypeID)
ON SubmissionLog.AccountID = Accounts.ID
GROUP BY Accounts.Name
Then you can join your main query to this sub-query by Accounts.Name and SubmissionLog.ID to the MaxID and that way you will get the additional columns restricted by the max submission id

SQL Outer Join on a bunch of Inner Joined results

I received some great help on joining a table to itself and am trying to take it to the next level. The SQL below is from the help but with my addition of the select line beginning with COUNT, the inner join to the Recipient table, and the Group By.
SELECT
Event.EventID AS EventID,
Event.EventDate AS EventDateUTC,
Participant2.ParticipantID AS AwayID,
Participant1.ParticipantID AS HostID,
COUNT(Recipient.ChallengeID) AS AllChallenges
FROM Event
INNER JOIN Matchup Matchup1
ON (Event.EventID = Matchup1.EventID)
INNER JOIN Matchup Matchup2
ON (Event.EventID = Matchup2.EventID)
INNER JOIN Participant Participant1
ON (Matchup1.Host = 1
AND Matchup1.ParticipantID = Participant1.ParticipantID)
INNER JOIN Participant Participant2
ON (Matchup2.Host != 1
AND Matchup2.ParticipantID = Participant2.ParticipantID)
INNER JOIN Recipient
ON (Event.EventID = Recipient.EventID)
WHERE Event.CategoryID = 1
AND Event.Resolved = 0
AND Event.Type = 1
GROUP BY Recipient.ChallengeID
ORDER BY EventDateUTC ASC
My goal is to get a count of how many rows in the Recipient table match the EventID in Event. This code works fine except that I also want to get results where there are 0 matching rows in Recipient. I want 15 rows (= the number of events) but I get 2 rows, one with a count of 1 and one with a count of 2 (which is appropriate for an inner join as there are 3 rows in the sample Recipient table, one for one EventID and two for another EventID).
I thought that either a LEFT join or an OUTER join was what I was looking for, but I know that I'm not quite getting how the tables are actually joined. A LEFT join there gives me one more row with 0, which happens to be EventID 1 (first thing in the table), but that's all. Errors advise me that I can't just change that INNER join to an OUTER. I tried some parenthesizing and some subselects and such but can't seem to make it work.
Use:
SELECT e.eventid,
e.eventdate AS EventDateUTC,
p2.participantid AS AwayID,
p1.participantid AS HostID,
COUNT(r.challengeid) AS AllChallenges
FROM EVENT e
JOIN Matchup m1 ON m1.eventid = e.eventid
AND m1.host = 1
JOIN Matchup m2 ON m2.eventid = e.eventid
AND m2.host != 1
JOIN Participant p1 ON p1.participantid = m1.participantid
JOIN Participant p2 ON p2.participantid = m2.participantid
LEFT JOIN RECIPIENT r ON r.eventid = e.eventid
WHERE e.categoryid = 1
AND e.resolved = 0
AND e.type = 1
GROUP BY e.eventid, e.eventdate, p2.participantid, p1.participantid
ORDER BY e.eventdate

Top 1 on Left Join SubQuery

I am trying to take a person and display their current insurance along with their former insurance. I guess one could say that I'm trying to flaten my view of customers or people. I'm running into an issue where I'm getting multiple records back due to multiple records existing within my left join subqueries. I had hoped I could solve this by adding "TOP 1" to the subquery, but that actually returns nothing...
Any ideas?
SELECT
p.person_id AS 'MIRID'
, p.firstname AS 'FIRST'
, p.lastname AS 'LAST'
, pg.name AS 'GROUP'
, e.name AS 'AOR'
, p.leaddate AS 'CONTACT DATE'
, [dbo].[GetPICampaignDisp](p.person_id, '2009') AS 'PI - 2009'
, [dbo].[GetPICampaignDisp](p.person_id, '2008') AS 'PI - 2008'
, [dbo].[GetPICampaignDisp](p.person_id, '2007') AS 'PI - 2007'
, a_disp.name AS 'CURR DISP'
, a_ins.name AS 'CURR INS'
, a_prodtype.name AS 'CURR INS TYPE'
, a_t.date AS 'CURR INS APP DATE'
, a_t.effdate AS 'CURR INS EFF DATE'
, b_disp.name AS 'PREV DISP'
, b_ins.name AS 'PREV INS'
, b_prodtype.name AS 'PREV INS TYPE'
, b_t.date AS 'PREV INS APP DATE'
, b_t.effdate AS 'PREV INS EFF DATE'
, b_t.termdate AS 'PREV INS TERM DATE'
FROM
[person] p
LEFT OUTER JOIN
[employee] e
ON
e.employee_id = p.agentofrecord_id
INNER JOIN
[dbo].[person_physician] pp
ON
p.person_id = pp.person_id
INNER JOIN
[dbo].[physician] ph
ON
ph.physician_id = pp.physician_id
INNER JOIN
[dbo].[clinic] c
ON
c.clinic_id = ph.clinic_id
INNER JOIN
[dbo].[d_Physgroup] pg
ON
pg.d_physgroup_id = c.physgroup_id
LEFT OUTER JOIN
(
SELECT
tr1.*
FROM
[transaction] tr1
LEFT OUTER JOIN
[d_vendor] ins1
ON
ins1.d_vendor_id = tr1.d_vendor_id
LEFT OUTER JOIN
[d_product_type] prodtype1
ON
prodtype1.d_product_type_id = tr1.d_product_type_id
LEFT OUTER JOIN
[d_commission_type] ctype1
ON
ctype1.d_commission_type_id = tr1.d_commission_type_id
WHERE
prodtype1.name <> 'Medicare Part D'
AND tr1.termdate IS NULL
) AS a_t
ON
a_t.person_id = p.person_id
LEFT OUTER JOIN
[d_vendor] a_ins
ON
a_ins.d_vendor_id = a_t.d_vendor_id
LEFT OUTER JOIN
[d_product_type] a_prodtype
ON
a_prodtype.d_product_type_id = a_t.d_product_type_id
LEFT OUTER JOIN
[d_commission_type] a_ctype
ON
a_ctype.d_commission_type_id = a_t.d_commission_type_id
LEFT OUTER JOIN
[d_disposition] a_disp
ON
a_disp.d_disposition_id = a_t.d_disposition_id
LEFT OUTER JOIN
(
SELECT
tr2.*
FROM
[transaction] tr2
LEFT OUTER JOIN
[d_vendor] ins2
ON
ins2.d_vendor_id = tr2.d_vendor_id
LEFT OUTER JOIN
[d_product_type] prodtype2
ON
prodtype2.d_product_type_id = tr2.d_product_type_id
LEFT OUTER JOIN
[d_commission_type] ctype2
ON
ctype2.d_commission_type_id = tr2.d_commission_type_id
WHERE
prodtype2.name <> 'Medicare Part D'
AND tr2.termdate IS NOT NULL
) AS b_t
ON
b_t.person_id = p.person_id
LEFT OUTER JOIN
[d_vendor] b_ins
ON
b_ins.d_vendor_id = b_t.d_vendor_id
LEFT OUTER JOIN
[d_product_type] b_prodtype
ON
b_prodtype.d_product_type_id = b_t.d_product_type_id
LEFT OUTER JOIN
[d_commission_type] b_ctype
ON
b_ctype.d_commission_type_id = b_t.d_commission_type_id
LEFT OUTER JOIN
[d_disposition] b_disp
ON
b_disp.d_disposition_id = b_t.d_disposition_id
WHERE
pg.d_physgroup_id = #PhysGroupID
In Sql server 2005 you can use OUTER APPLY
SELECT p.person_id, s.e.employee_id
FROM person p
OUTER APPLY (SELECT TOP 1 *
FROM Employee
WHERE /*JOINCONDITION*/
ORDER BY /*Something*/ DESC) s
http://technet.microsoft.com/en-us/library/ms175156.aspx
The pattern I normally use for this is:
SELECT whatever
FROM person
LEFT JOIN subtable AS s1
ON s1.personid = person.personid
...
WHERE NOT EXISTS
( SELECT 1 FROM subtable
WHERE personid = person.personid
AND orderbydate > s1.orderbydate
)
Which avoids the TOP 1 clause and maybe makes it a little clearer.
BTW, I like the way you've put this query together in general, except I'd leave out the brackets, assuming you have rationally named tables and columns; and you might even gain some performance (but at least elegance) by listing columns for tr1 and tr2, rather than "tr1.*" and "tr2.*".
Thanks for all of the feedback and ideas...
In the simplest of terms, I have a person table that stores contact information like name, email, etc. I have another table that stores transactions. Each transaction is really an insurance policy that would contain information on the provider, product type, product name, etc.
I want to avoid giving the user duplicate person records since this causes them to look for the duplicates prior to running mail merges, etc. I'm getting duplicates when there is more than 1 transaction that has not been terminated, and when there is more than 1 transaction that has been terminated.
Someone else suggested that I consider a cursor to grab my distinct contact records and then perform the sub selects to get the current and previous insurance information. I don't know if I want to head down that path though.
It's difficult to understand your question so first I'll throw this out there: does changing your SELECT to SELECT DISTINCT do what you want?
Otherwise, let me get this straight, you're trying to get your customers' current insurance and previous insurance, but they may actually have many insurances before that, recorded in the [transactions] table? I looked at your SQL for quite a few minutes but can't figure out what it all means, so could you please reduce it down to only the parts that are necessary? Then I'll think about it some more. It sounds to me like you need a GROUP BY somehow, but I can't work it out exactly yet.
Couldn't take the time to dig through all your SQL (what a beast!), here's an idea that might make things easier to handle:
select
p.person_id, p.name <and other person columns>,
(select <current policy columns>
from pol <and other tables for policy>
where pol.<columns for join> = p.person_id
and <restrictions for current policy>),
(select <previous policy columns>
from pol <and other tables for policy>
where pol.<columns for join> = p.person_id
and <restrictions for previouspolicy>),
<other columns>
from person p <and "directly related" tables>
This makes the statement easier to read by separating the different parts into their own subselects, and it also makes it easier to add a "Top 1" in without affecting the rest of the statement. Hope that helps.