简体   繁体   中英

SQL: Iterate through subquery

I'm currently working on a query that flags all the orders that don't have the same email address as any other order within the last 10 days.

Now I can check if the last order is less than 10 days old or not but if there are 3 orders:

1. 2019/01/01
2. 2019/01/20
3. 2019/01/22

Then all of them will get a yes because nr 3 will check nr 1. So I need to build a loop inside the subquery to iterate through all the ones with the same email address. Please help:)

SELECT TOP (1000)       
        OnlyOneWithin10Days =  
                CASE   
                WHEN (select top (1) inner.CreationDate 
                    from [Database].[req].[PersonalDetail] as pd1 
                    JOIN req.OfferRequest ofreq on ofreq.MainDriverPersonalDetailID = inner.ID
                    JOIN rsp.InsuranceResponse inresp on ofreq.InsuranceResponseID = inresp.id
                    JOIN adm.ProductBundle inner2 on inresp.ProductBundleID = inner2.ID
                    where inner.Email = personalDetail.Email 
                    and inner2.ID = pb.ID
                    and personalDetail.id > inner.ID
                    and inner.CreationDate < personalDetail.CreationDate
                    order by inner.CreationDate desc) is NULL

                OR  datediff(MINUTE, (select top (1) inner.CreationDate 
                    from [Database].[req].[PersonalDetail] as inner 
                    JOIN req.OfferRequest ofreq on ofreq.MainDriverPersonalDetailID = inner.ID
                    JOIN rsp.InsuranceResponse inresp on ofreq.InsuranceResponseID = inresp.id
                    JOIN adm.ProductBundle inner2 on inresp.ProductBundleID = inner2.ID
                    where inner.Email = personalDetail.Email 
                    and inner2.ID = pb.ID
                    and personalDetail.id > inner.ID
                    and inner.CreationDate < personalDetail.CreationDate
                    --and datediff(MINUTE, inner.CreationDate, personalDetail.CreationDate) >= 10
                    order by inner.CreationDate desc), personalDetail.CreationDate) >= 10

                THEN 'Yes'
                ELSE 'No'
                END 
        ,personalDetail.CreationDate
        ,pb.Name product
        ,personalDetail.Name
        ,personalDetail.email
        ,i.Name insurance

  FROM [Database].[req].[OfferRequest] as oreq

  JOIN req.PersonalDetail personalDetail on oreq.MainDriverPersonalDetailID = personalDetail.ID
  JOIN rsp.InsuranceResponse ir on oreq.InsuranceResponseID = ir.ID
  JOIN adm.ProductBundle pb on ir.ProductBundleID = pb.ID
  JOIN adm.Insurance i on pb.InsuranceID = i.ID


  order by personalDetail.Email, personalDetail.CreationDate

Edit: I`m using SSMS (Microsoft SQL Server Management Studio 14.0.17289.0)

Edit2: Sorry if my question is a bit confusing but I`m new to stackOverflow.

The result should look something like this

在此处输入图片说明

You posted what you want so here is how to do it -- see below for details about how this works from before you were specific about what exactly you wanted:

SELECT TABLE1.*, CASE WHEN SUB.PRIOR = 0 THEN 'YES' ELSE 'NO' END AS OnlyEmail10days 
FROM TABLE1 
JOIN (
  SELECT BASE.EMAIL, COUNT(PROIR.EMAIL) AS PRIOR
  FROM TABLE1 AS BASE
  LEFT JOIN TABLE1 AS PRIOR ON BASE.EMAIL = PROIR.EMAIL AND DATEDIFF(day, PRIOR.DATE, BASE.DATE) <= 10
  GROUP BY BASE.EMAIL
) AS SUB ON SUB.EMAIL = TABLE1.EMAIL

Of course TABLE1.* is a placeholder here, but in the exact fields you want from TABLE1.


I don't understand your code, but here is an answer to your question:

Lets say you have table call TABLE1 and it has a field called EMAIL and a field called DATE

The following query

 SELECT BASE.EMAIL, COUNT(PRIOR.EMAIL) AS CNT
 FROM TABLE1 AS BASE
 JOIN TABLE1 AS PRIOR ON BASE.EMAIL = PROIR.EMAIL AND DATEDIFF(day, PRIOR.DATE, BASE.DATE) <= 10
 GROUP BY BASE.EMAIL

Will return all rows with the same email in the last 10 days and a count of how many.

Hope this helps. This is how SQL works, it uses sets not iteration.

The way it works is using joins -- joining is a set function -- we define the criteria for the set of items which are the same email and 10 days and SQL finds all of them at once. We only want a count of them so that is what we return (if you don't need the count just leave that field out of the result set.)

If you only want items that don't have an email address in the last 10 days use this query:

 SELECT BASE.EMAIL
 FROM TABLE1 AS BASE
 LEFT JOIN TABLE1 AS PRIOR ON BASE.EMAIL = PROIR.EMAIL AND DATEDIFF(day, PRIOR.DATE, BASE.DATE) <= 10
 WHERE PRIOR.EMAIL IS NULL

Here we do the same as before but because it is a left join we can take the set that does not have any joining elements.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM