MS SQL - 3 'OR's within one OR - sql

I have a View I created using Microsoft Dynamics 2011 and I'm now looking to turn this into SQL code to use within Excel.
I have gotten everything else to work except the OR clauses (the query doesn't return all the results that I am expecting). I'm very new to SQl and any help will be really appreciated.
AND (Child.btb_childhealthlastlacmedical is NULL
OR Child.btb_childhealthlastlacmedical <= DATEADD(month, -12, GETDATE()))
AND (Child.btb_childhealthlastdentaldate is NULL
OR Child.btb_childhealthlastdentaldate <= DATEADD(month, -12, GETDATE()))
AND (Child.btb_childhealthlastopticiandate is NULL
OR Child.btb_childhealthlastopticiandate <= DATEADD(month, -24, GETDATE()))
Final Edit Solved By xQbert's solution below. Thank you so much!!

I think you're looking for something more like this. But you might possibly want and instead or or within the brackets. Not sure what you're looking for. But basically you need to separate statements with or instead of and
AND (Child.btb_childhealthlastlacmedical is NULL OR
Child.btb_childhealthlastlacmedical <= DATEADD(month, -12, GETDATE()))
OR
(Child.btb_childhealthlastdentaldate is NULL OR
Child.btb_childhealthlastdentaldate <= DATEADD(month, -12, GETDATE()))
OR
(Child.btb_childhealthlastopticiandate is NULL OR
Child.btb_childhealthlastopticiandate <= DATEADD(month, -24, GETDATE()))

This will return true if any field meets the criteria
AND ( COALESCE(Child.btb_childhealthlastlacmedical,
DATEADD(month, -12, GETDATE())) <= DATEADD(month, -12, GETDATE())
OR COALESCE(Child.btb_childhealthlastdentaldate ,
DATEADD(month, -12, GETDATE())) <= DATEADD(month, -12, GETDATE())
OR COALESCE(Child.btb_childhealthlastopticiandate ,
DATEADD(month, -12, GETDATE())) <= DATEADD(month, -24, GETDATE())
)
You also want to change your RIGHT outer join to just a JOIN (sometimes called an inner join) This is probably why you are getting more results than you expect.

Don't mix join notations use the ANSI 92 standard (INNER JOIN, OUTER JOIN) not the 89 (comma notation) your present join would exclude the records from the family table not in filtered contact.
--RIGHT OUTER JOINS mean that dbo.FilteredContactcontact is the table with all the records. And then records from dbo.filteredAccount that match those in child and then those in filteredBusinessUnit that match. As such the fil.name filter belongs on the join.
The filters on the child table belong on the right table. I'm really surprised no one else caught me on this...
SELECT Child.fullname AS Child
FROM dbo.FilteredBusinessUnit Fil
RIGHT JOIN dbo.FilteredAccount Family
ON Fil.businessunitid=Family.owningbusinessunit
RIGHT JOIN dbo.FilteredContact Child
ON Child.accountid=Family.accountid
WHERE (Child.btb_childhealthlastlacmedical is NULL
OR Child.btb_childhealthlastlacmedical <= DATEADD(month, -12, GETDATE())
OR Child.btb_childhealthlastdentaldate is NULL
OR Child.btb_childhealthlastdentaldate <= DATEADD(month, -12, GETDATE())
OR Child.btb_childhealthlastopticiandate is NULL
OR Child.btb_childhealthlastopticiandate <= DATEADD(month, -24, GETDATE()) )
AND Child.customertypecode = 1
AND Child.owningbusinessunit = 'North West'
Note when using outer joins, any limiting criteria on tables aside from the "all records table (FilteredContactin this case)" should be placed on the join, or the outer join is negated and behaves like an inner join.
I'm not sure why you have the null checks if its because some records are null or if you had the null check to keep the records from the outer join. If the latter then this way we don't need the null checks. If the first then we need to keep the null checks.

Related

How to go back two days from a date in sql?

I wrote an SQL query that allows me to get the sales of certain stores.
My query runs every mornings and I would like to get the sales from 2 days ago at runtime.
For example if my query runs tomorrow morning, on 08/12, I would like to have the sales whose value in the column "GP_HEURECREATION" starts with "20200612", to have all the sales of the whole day.
The GP_HEURECREATION column has a format like this: "20200612 00:00:00" and is of the DATE type.
I tried with NOW() and DATEADD() but I have 2018 values that stand out for example.
How can I get the values only two days before the query is executed?
SELECT
T_ETABLISSEMENT, ET1.ET_LIBELLE AS C1, GL_ETABLISSEMENT,
GP_HEURECREATION, GP_REFINTERNE, GL_CODEARTICLE,
LIBDIM2, LIBDIM1, GL_QTEFACT, GL_PUTTC,
(GL_TOTALHT * GP_COTATIONDOS) AS TOTALHTDEV, GL_DPR, GL_DEVISE,
GL_NATUREPIECEG, GA_LIBELLE
FROM
GCLIGNEARTDIM
LEFT OUTER JOIN
PGI_LOOKUP(TTETABLISSEMENT) ET1 ON GL_ETABLISSEMENT = ET1.ET_ETABLISSEMENT
WHERE
(GP_HEURECREATION <= DATEADD(day, -2, GETDATE())
AND (GL_NATUREPIECEG = "FFO")
AND GL_ETABLISSEMENT = "20897", "10519", "20267", "26451", "20269", "26078", "28047", "20900", "28085", "24984", "27113", "20268", "19994", "28450", "26876", "24063", "18066", "3220"
ORDER BY
GP_REFINTERNE
The syntax of your existing query suggests SQL Server. If you want records that belong to day -2, you can do:
where gp_heurecreation >= dateadd(day, -2, convert(date, getdate()))
and gp_heurecreation < dateadd(day, -1, convert(date, getdate()))
If gp_heurecreation has no time component (in SQL Server, that's a date datatype), this is simpler:
where gp_heurecreation = dateadd(day, -2, convert(date, getdate()))

Date Statement Issue

I am not a SQL expert at all...we are trying to us the following to pull data from the previous week. I am fairly certain the 4 is incorrect, as we want data from Sunday through Saturday. The statement that was created was:
SELECT * FROM Table
Where [Date] Between DATEADD(wk,DATEDIFF(wk,7,GETDATE()),0) AND
DATEADD(wk,DATEDIFF(wk,7,GETDATE()),4)
Assuming you are working on Sql Server, you can use cte structure like below, set regarding data into cte and filter in your main query:
;with cte (ID) as ( --data from previous week only
Select Id from table
Where [Date] >= DATEADD(WEEK,-1,DATEADD(week,datediff(week,0,getdate()),0))
AND [Date] < DATEADD(week,datediff(week,0,getdate()),0)
)
select *
from table t
inner join cte on t.Id = cte.ID
where DATEPART(DW, [Date]) >= 0 --sunday
and DATEPART(DW, [Date]) <= 6 --saturday
In the filter, edit 0 and 6 to filter your data based on date as you wish.
If you use this, it returns previous Saturday and Sunday:
SELECT DATENAME(DW,(DATEADD(day, -6, getdate()))) ,DATENAME(DW,(DATEADD(day, -5,
getdate())))
[![Day Name][1]][1]
So, for example, you can use DATEADD(day, -6, getdate()) to get Saturday.

Sum on case expression when working with dates

I'm looking to create a view which will output the data in the following format
AgedPeriod BillValue Status
<1 35000 Outstanding
1-3 23386 Outstanding
3-6 5000 Outstanding
I can use the code below to SUM each case statement into a new column and I could name the column headings after the AgedPeriod listed above but even though the SUMS are right the format is wrong I would like to have the code below nested in another CASE statement that does not have to be GROUPED by b.BILL_DATE as grouping with the bill date defeats the purpose of my SUM. All attempts as using another CASE statement always bring the b.BILL_DATE out of the SUM and into the WHEN condition requiring it to be grouped.
SELECT
SUM(CASE WHEN (b.BILL_DATE <= GetDate()
AND b.BILL_DATE >= DateAdd(mm,-1, GetDate()))
THEN b.OUTSTANDING END),
SUM(CASE WHEN (b.BILL_DATE <= DateAdd(mm,-1, GetDate())
AND b.BILL_DATE >= DateAdd(mm,-3, GetDate()))
THEN b.OUTSTANDING END),
SUM(CASE WHEN (b.BILL_DATE <= DateAdd(mm,-3, GetDate())
AND b.BILL_DATE >= DateAdd(mm,-6, GetDate()))
THEN b.OUTSTANDING END)
FROM dbo.Tables
I understand this may not be achievable with the route that I have taken at present but is there be any other way I can SUM the outstanding amount on each time period? I can deal with the status column (no advice needed there)
I have added a table and some sample data and left a query to show how I would want the data split up but it would want it to be formatted as above (in a column)
Example on Sql Fiddle
Thanks
You want a group by rather than conditional aggregation. The query you want is something like this:
SELECT (CASE WHEN b.BILL_DATE >= DateAdd(month,-1, GetDate())
THEN '<1'
WHEN b.BILL_DATE >= DateAdd(month, -3, GetDate())
THEN '1-3'
WHEN b.BILL_DATE >= DateAdd(month, -6, GetDate())
THEN '3-6'
ELSE '6+'
END) as AgedPeriod,
SUM(Outstanding)
FROM dbo.Tables b
WHERE b.BILL_DATE <= GetDate()
GROUP BY (CASE WHEN b.BILL_DATE >= DateAdd(month,-1, GetDate())
THEN '<1'
WHEN b.BILL_DATE >= DateAdd(month, -3, GetDate())
THEN '1-3'
WHEN b.BILL_DATE >= DateAdd(month, -6, GetDate())
THEN '3-6'
ELSE '6+'
END);
Notes:
The groups are defined by a CASE statement. Because this is evaluated in order, you can simplify the logic.
The common condition b.BILL_DATE <= GetDate() is moved to the WHERE clause.
I added an extra condition for longer than six months. It seems like you wouldn't want to ignore these.
I don't know what the final column is supposed to be.
You could either use a subquery or CTE to perform the case when statement and then join back to the base table to get the sum for the outstanding column like this:
SELECT a.AgedPeriod
,sum(t1.Outstanding) BillValue
,a.[Status]
FROM dbo.Bill t1
JOIN (
SELECT (
CASE
WHEN b.BILLDATE >= DateAdd(month, - 1, GetDate())
THEN '<1'
WHEN b.BILLDATE >= DateAdd(month, - 3, GetDate())
THEN '1-3'
WHEN b.BILLDATE >= DateAdd(month, - 6, GetDate())
THEN '3-6'
ELSE '6+'
END
) AS AgedPeriod
,b.[ID]
,'Outstanding' [Status]
FROM dbo.Bill b
WHERE b.BILLDATE <= GetDate()
) a ON a.[ID] = t1.[ID]
GROUP BY a.AgedPeriod
,a.[Status]
Hope this helps! Here is a SQL Fiddle Demo for this:
SQL Fiddle Solution Demo

select month and year from Date of birth IN sql

i have table with DOB column ('2012-05-29 00:00:00.000') and few other fields , i need to select the data for DOB between 6 months to 6 Years. I tried using the below SQL but this is not giving me the right data. any help will be appreciated.
select * from dbo.xyz
where ( FLOOR(DATEDIFF(MONTH, birth_date , GETDATE()) % 12) >=6
AND FLOOR(DATEDIFF(DAY, birth_date , GETDATE()) / 365.25) <= 6
)
When using dates, the advice is to use functions only on the non-column values. In other words, modify getdate(), not birth_date:
select *
from dbo.xyz
where birth_date between dateadd(year, -6, getdate()) and dateadd(month, -6, getdate())
This has two advantages. First, it makes the where clause "sargable", which means an index can be used on the comparison. More importantly, the alternative of using datediff() doesn't quite work as expected. datediff() counts the number of calendar boundaries between two values. So, 2014-12-31 and 2015-01-01 are one day apart, one month apart, and even one year apart.
Try this
select * from dbo.xyz
where DATEDIFF(MONTH, birth_date , GETDATE()) between 6 and 72
Here is another option that will allow indexing on birthdate.
select *
from dbo.xyz
where birthdate > DATEADD(YEAR, -6, GETDATE())
and birthdate < DATEADD(MONTH, -6, GETDATE())

Weekly to Monthly Reports

I was running weekly reports as in the below script. However, I now want to run monthly report so needed some assistance.
Weekly:
SELECT * FROM TABLE WHERE
(ARRIVAL_DATE>GETDATE()-7)//7 days before
AND
(ARRIVAL_DATE<GETDATE()) //NOW
For monthly report, will below script be right if I run on every 1st?
SELECT Column1,...
FROM TableName
WHERE
MONTH(DateColumn) = MONTH(dateadd(dd, -1, GetDate()))
AND
YEAR(DateColumn) = YEAR(dateadd(dd, -1, GetDate()))
Thanks.
Your logic looks okay, although I would use day instead of dd, because I think it is clearer.
However, your query will prevent the use of an index on datecolumn. The following is a "better" form of the logic, because it allows the use of an index:
where datecolumn >= dateadd(month, -1,
dateadd(day, 1 - day(getdate()), cast(getdate() as date))
) and
datecolumn < dateadd(day, 1 - day(getdate()), cast(getdate() as date))
This looks more complicated, but all the functions are on getdate(), so the engine can use an index. Also note the explicit conversion to date. getdate() returns a time component which might throw off the logic if datecolumn only has a date.
where datecolumn between dateadd(mm, -1,getdate()) and getdate()