substract a day from a date based on a condition - sql

I would like to display an output when a certain column which contain dates equals the last day of a month then another column which also contains other dates should equal the same date minus 1 day
SELECT
CASE WHEN s.audit_date <> null
THEN us.processing_date = s.audit_date - 1 END processing_date
, g.mobile_no
FROM customers cu
INNER JOIN gsm.mobile_no g ON g.id = cu.id;
but unfortunately this doesn't work..

There are a couple of problems that I can see with your query.
You are missing a comma after the s.audit_date to provide valid T-SQL syntax
In your CASE statement you are attempting to set a column value, just return the value you want.
select us.processing_date, s.audit_date,
CASE
WHEN s.audit_date = trunc(s.audit_date, 'MM') THEN s.audit_date - 1
END processing_date, g.mobile_no
from customers cu
inner join gsm.mobile_no g on g.id = cu.id

Among other things, I think you need an else clause and to fix the comparison to NULL:
select (case when s.audit_date is not null then s.audit_date - 1
else s.processing_date
end) as processing_date, g.mobile_no
from customers cu inner join
gsm.mobile_no g
on g.id = cu.id;

Related

How to Grab Specific Row info?

The below is an example of what will output when you run the query open: select A.DispatchNote, A.MStockCode, A.NComment
from MdnMaster
MdnMaster.DispatchNote
MdnMaster.MStockCode
MdnMaster.NComment
12345/001
CAL2-01234-010-50L
12345/001
FREIGHT
12345/001
1 Parcel
12345/001
Trk# 1Z8R9V80013141323 - 5 lb
12345/001
Trk#: 1Z8R9V900381868191 -- 18 lb
12345/001
SHP 21401
12345/002
CAL3-0121-020-50L
12345/002
FREIGHT
12345/002
2 Parcels
12345/002
Trk# 1Z8R9V80013141323 - 5 lb
12345/002
Trk#: 1Z8R9V900381868191 -- 18 lb
12345/002
SHP 2140
I'm trying to do a query that'll grab just the first tracking number in the list. and ignore the second (or sometimes third they have)
The database has blank NComment lines when there's an MStockCode, and then the MStockCode lines are blank for every NComment line so I don't know what I'm doing.
What I have so far:
SELECT
m.DispatchNote,
MAX(d.MStockCode) as StockCode,
MAX(case when d.NComment like 'Trk%' then d.NComment end) as NComment,
MAX(m.CustomerPoNumber) as CustomerPO
FROM MdnMaster AS m
LEFT OUTER JOIN MdnDetail AS d on m.DispatchNote = d.DispatchNote
AND (d.NComment LIKE 'Trk%' OR d.MStockCode is not null)
and m.Customer = 'LAWSON'
and d.MLineShipDate =
case
when datepart(weekday, getdate() -1) = '7'
then DATEADD(hh,0,dateadd(DAY, datediff(day, 0, getdate()),-2)) -- if yesterday was Saturday, set to Friday
when datepart(weekday, getdate() -1) = '1'
then DATEADD(hh,0,dateadd(DAY, datediff(day, 0, getdate()),-3)) -- if yesterday was Sunday, set to Friday
else DATEADD(hh,0,dateadd(DAY, datediff(day, 0, getdate()),-1))
end
GROUP BY m.DispatchNote
My issue is that it gives me nothing since I only know how to ask it explicitly that I want the lines that aren't blank. How do I fix it?
EDIT: I should mention that all of the information comes from the MdnMaster Table (which is A) and MLineShipDate will come from B (MdnDetail). I omitted that information because I didn't think it was pertinent to the question at hand.
An example of what I want to see FROM above:
MdnMaster.DispatchNote
MdnMaster.MStockCode
MdnMaster.NComment
12345/001
CAL2-01234-010-50L
Trk# 1Z8R9V80013141323 - 5 lb
Here's a quick way to get some results. Hopefully, it will set you on the right path.
I'm assuming you can specify a second column to determine the order of the comments. Replace all instances of Line below with the actual column name.
Select
m1.DispatchNote,
m3.MStockCode,
m1.NComment
From
MdnMaster m1
Inner Join (
Select DispatchNote, Min(Line) as Line
From MdnMaster
Where NComment like 'Trk%'
Group by DispatchNote ) m2
on m1.DispatchNote = m2.DispatchNote and m1.Line = m2.Line
Inner Join (
Select DispatchNote, Max(MStockCode) as MStockCode
From MdnMaster
Group by DispatchNote ) m3
on m1.DispatchNote = m3.DispatchNote
One approach use a cross apply together with select top 1 to retrieve the tracking number.
select M.DispatchNote, M.MStockCode, TRK.NComment
from MdnMaster M
cross apply (
select top 1 M2.NComment
from MdnMaster M2
where M2.DispatchNote = M.DispatchNote
and M2.NComment LIKE 'Trk# %'
-- order by ?
) TRK
where M.MStockCode <> ''
Another approach is to join to a subselect that selects all tracking numbers and assigns row numbers withing each group. The final select would limit itself to those tracking numbers where row number = 1.
select M.DispatchNote, M.MStockCode, TRK.NComment
from MdnMaster M
join (
select M2.DispatchNote, M2.NComment,
row_number() OVER(PARTITION BY M2.DispatchNote order by (select null)) as RN
from MdnMaster M2
where M2.NComment LIKE 'Trk# %'
) TRK ON TRK.DispatchNote = M.DispatchNote
where M.MStockCode <> ''
and TRK.RN = 1
See this db<>fiddle for examples of both.
If there is a chance that there is no tracking number, but you still want to include the other results, change cross apply to outer apply in the first query, or the join to a left join in the second. A cross apply is like an inner join to a subselect, while an outer apply is like a left join.
If you have criteria that prefers one tracking number over another, include it in the order by clause of the subselect in the first query, or replace the order by (select null) placeholder clause in the second. Otherwise, an arbitrary tracking number will be selected.

How to force postgres to return 0 even if there are no rows matching query, using coalesce, group by and join

I've been trying hopelessly to get the following SQL statement to return the query results and default to 0 if there are no rows matching the query.
This is the intended result:
vol | year
-------+------
0 | 2018
Instead I get:
vol | year
-----+------
(0 rows)
Here is the sql statement:
select coalesce(vol,0) as vol, year
from (select sum(vol) as vol, year
from schema.fact_data
join schema.period_data
on schema.fact_data.period_tag = schema.period_data.tag
join schema.product_data
on schema.fact_data.product_tag =
schema.product_data.tag
join schema.market_data
on schema.fact_data.market_tag = schema.market_data.tag
where "retailer"='MadeUpRetailer'
and "product_tag"='FakeProductTag'
and "year"='2018' group by year
) as DerivedTable;
I know the query works because it returns data when there is data. Just doesn't default to 0 as intended...
Any help in finding why this is the case would be much appreciated!
Using your subquery DerivedTable, you could write:
SELECT coalesce(DerivedTable.vol, 0) AS vol,
y.year
FROM (VALUES ('2018'::text)) AS y(year)
LEFT JOIN (SELECT ...) AS DerivedTable
ON DerivedTable.year = y.year;
Remove the GROUP BY (and the outer query):
select 2018 as year, coalesce(sum(vol), 0) as vol
from schema.fact_data f join
schema.period_data p
on f.period_tag = p.tag join
schema.product_data pr
on f.product_tag = pr.tag join
schema.market_data m
on fd.market_tag = m.tag
where "retailer" = 'MadeUpRetailer' and
"product_tag" = 'FakeProductTag' and
"year" = '2018';
An aggregation query with no GROUP BY always returns exactly one row, so this should do what you want.
EDIT:
The query would look something like this:
select v.yyyy as year, coalesce(sum(vol), 0) as vol
from (values (2018), (2019)) v(yyyy) left join
schema.fact_data f
on f.year = v.yyyy left join -- this is just an example. I have no idea where year is coming from
schema.period_data p
on f.period_tag = p.tag left join
schema.product_data pr
on f.product_tag = pr.tag left join
schema.market_data m
on fd.market_tag = m.tag
group by v.yyyy
However, you have to move the where conditions to the appropriate on clauses. I have no idea where the columns are coming from.
From the code you posted it is not clear in which table you have the year column.
You can use UNION to fetch just 1 row in case there are no rows in that table for the year 2018 like this:
select sum(vol) as vol, year
from schema.fact_data innrt join schema.period_data
on schema.fact_data.period_tag = schema.period_data.tag
inner join schema.product_data
on schema.fact_data.product_tag = schema.product_data.tag
inner join schema.market_data
on schema.fact_data.market_tag = schema.market_data.tag
where
"retailer"='MadeUpRetailer' and
"product_tag"='FakeProductTag' and
"year"='2018'
group by "year"
union
select 0 as vol, '2018' as year
where not exists (
select 1 from tablename where "year" = '2018'
)
In case there are rows for the year 2018, then nothing will be fetched by the 2nd query,

Teradata SQL CASE Statement with multiple conditions

I have the below SQL query -
select distinct HospitalAcctID,
AdmitDate,
DischargeDate,
PatMRN,
Pat_id,
ICD,
MedCenter,
(case when SeqCount =1 and AdmitDate > '06/01/2013' and AdmitDate < '06/01/2018' then 1 else null end ) Firstdiag
from
(
select distinct acct.HSP_ACCOUNT_ID as HospitalAcctID,
cast(acct.ADM_DATE_TIME as date format 'mm/dd/yyyy') as AdmitDate,
cast(acct.DISCH_DATE_TIME as date format 'mm/dd/yyyy') as DischargeDate,
pat.pat_mrn_id as PatMRN,
pat.pat_id as Pat_id,
REF_BILL_CODE as ICD,
grp7.NAME AS MedCenter,
row_number() over (partition by PatMRN order by AdmitDate) as SeqCount
from acct
inner join pat on pat.pat_id = acct.pat_id
inner join hspenc on hspenc.CSN_ID = acct.CSN_ID
inner join dx on acct.ACCOUNT_ID = dx.ACCOUNT_ID and line = 1
inner join edg on dx.DX_ID = edg.DX_ID
inner join loc on loc.LOC_ID = acct.LOC_ID
inner join grp7 ON loc.RPT_GRP_SEVEN = grp7.RPT_GRP_SEVEN
where
grp7.NAME = 'SMC AREA'
and ADMIT_CONF_STAT_C in ('1','4')
and (edg. REF_BILL_CODE in ('431',
'431')
)
and ADT_PAT_CLASS_C in ('1204','12113')
order by AdmitDate;
)Admit
But I am getting the below syntax error -
Syntax error, expected something like an 'EXCEPT' keyword, 'UNION' Keyword or a 'MINUS' keyword between 'AdmitDate' and ','
In the outer select statement, I am trying to get the min (first ) date when the was first diagnosed. I also want to get only the patients who were diagnosed between 6/2013 to 6/2018 which is why I have the CASE statement. But the CASE statement is giving me error.
As #BarbarosĂ–zhan already wrote, remove the last line order by AdmitDate; in the Derived Table.
But there's no need for ROW_NUMBER:
select distinct acct.HSP_ACCOUNT_ID as HospitalAcctID,
cast(acct.ADM_DATE_TIME as date format 'mm/dd/yyyy') as AdmitDate,
cast(acct.DISCH_DATE_TIME as date format 'mm/dd/yyyy') as DischargeDate,
pat.pat_mrn_id as PatMRN,
pat.pat_id as Pat_id,
REF_BILL_CODE as ICD,
grp7.NAME AS MedCenter,
case when -- current rows is first row
min(AdmitDate)
over (partition by PatMRN) = AdminDate
-- current row within date range
and AdminDate >= DATE '2013-06-01' and AdmitDate < DATE '2018-06-01'
then 1
else null
end as Firstdiag
from acct
inner join pat on pat.pat_id = acct.pat_id
inner join hspenc on hspenc.CSN_ID = acct.CSN_ID
inner join dx on acct.ACCOUNT_ID = dx.ACCOUNT_ID and line = 1
inner join edg on dx.DX_ID = edg.DX_ID
inner join loc on loc.LOC_ID = acct.LOC_ID
inner join grp7 ON loc.RPT_GRP_SEVEN = grp7.RPT_GRP_SEVEN
where
grp7.NAME = 'SMC AREA'
and ADMIT_CONF_STAT_C in ('1','4')
and (edg. REF_BILL_CODE in ('431',
'431')
)
and ADT_PAT_CLASS_C in ('1204','12113')
order by AdmitDate;
I also switched to a Standard SQL date literal DATE '2013-06-01' instead of '06/01/2013'. There's only one possible format for the former (DATE 'YYYY-MM-DD') while the latter depends on the FORMAT of the base column and might fail when it changes (of course not in your query, because you defined it in the CAST).

How to fix "Conversion from string "August" to type 'Date' is not vaid in SSRS

SELECT
a.ItemCode,
SUM(a.NoOfApplication) AS NoOfApplication,
SUM(a.NoOfAccomplished) AS NoOfAccomplished,
SUM(a.NoOfPending) AS NoOfPending,
SUM(a.NoOfDocumentCompliance) AS NoOfDocumentCompliance,
a.[Year]
FROM
(SELECT
ItemCode,
COUNT(am.ReferenceNumber) AS NoOfApplication,
COUNT(TNA.NoOfAccomplished) AS NoOfAccomplished,
COUNT(TNP.NoOfPending) AS NoOfPending,
SUM(FDC.NoOfDocumentCompliance) AS NoOfDocumentCompliance,
DATENAME(month, ad.applicationdate) AS [Year]
FROM
AppTypes at
INNER JOIN
AssessmentMainDetails am ON at.Category = am.Category
INNER JOIN
InspectionProcesses i ON am.ReferenceNumber = i.ReferenceNo
LEFT JOIN
(SELECT
COUNT(Status) AS NoOfDocumentCompliance,
ReferenceNumber, Status
FROM
ApplicationStatus
WHERE
Status = 'For Document Compliance'
GROUP BY
ReferenceNumber, Status) AS FDC ON FDC.ReferenceNumber = i.ReferenceNo
LEFT JOIN
(SELECT
COUNT(ReferenceNo) AS NoOfAccomplished,
ReferenceNo
FROM
InspectionProcesses
WHERE
DateOfInspection <> ''
GROUP BY
ReferenceNo) AS TNA ON TNA.ReferenceNo = i.ReferenceNo
LEFT JOIN
(SELECT
COUNT(ReferenceNo) AS NoOfPending, ReferenceNo
FROM
InspectionProcesses
WHERE
DateOfInspection = ''
GROUP BY
ReferenceNo) AS TNP ON TNP.ReferenceNo = i.ReferenceNo
INNER JOIN
ApplicationDetails ad on i.ReferenceNo = ad.ReferenceNumber
INNER JOIN
Companies c on ad.CompanyId = c.CompanyID
INNER JOIN
Zones z on c.zonecode = z.zonecode
INNER JOIN
ZoneGroups zg on z.ZoneGroup = zg.ZoneGroupId
WHERE
DateOfInspection = ''
AND ad.ApplicationDate BETWEEN '2017-08-01' AND '2017-09-30'
AND zg.ZoneGroupCode = 'HO'
AND z.ZoneCode = 'VIDC'
GROUP BY
ItemCode, DATENAME(month, ad.applicationdate)) a
GROUP BY
a.ItemCode, a.[Year]
This my code, I already converted my date to get the month name. Please I need help
Look carefully. That giant derived table (a - nice meaningful name btw) has the same group by clause as the outermost query. So that means that [a] has a single row per ItemCode and datename(month, ad.applicationdate). Therefore, there is nothing to sum in your outer query since it is grouping by the same columns.
You also have the expression:
DateOfInspection = ''
which is highly suspicious based on the name of the column. What datatype is the DateOfInspection column? Doesn't sound like it should be string-based.
And lastly, the error message you posted sounds like it comes from SSRS and not sql server. Is that the case? Does your query run correctly from SSMS? Then the problem is in your report - and it would seem that you attempt to manipulate or interpret the Year column as a date (perhaps for sorting?). It also seems a bit short-sighted in your report design that your "Year" column is actually the name of a month and that your resultset does not include the year in some fashion. What happens when your data spans more than twelve months? And how do you intend to sort your report when you have month name but not month number?

SQL UNION query not working

here is my current queries:
1
SELECT FilteredInvoice.accountidname,
FilteredInvoice.createdon,
FilteredInvoice.createdon AS sort_date,
FilteredInvoice.duedate,
FilteredInvoice.invoicenumber,
FilteredInvoice.statecodename,
FilteredInvoice.totalamount_base,
CONVERT(datetime, NULL) AS mag_paymentdate,
0 AS mag_amount_base,
GETDATE() AS Today
FROM FilteredAccount AS CRMAF_FilteredAccount
JOIN FilteredInvoice ON FilteredInvoice.accountid = CRMAF_FilteredAccount.accountid
JOIN FilteredMag_Payment ON FilteredInvoice.invoiceid = FilteredMag_Payment.mag_invoiceid
WHERE (FilteredInvoice.statecodename <> 'Canceled')
2
SELECT FilteredInvoice_1.accountidname,
FilteredInvoice_1.createdon,
FilteredInvoice_1.createdon AS sort_date,
FilteredInvoice_1.duedate,
FilteredInvoice_1.invoicenumber,
FilteredInvoice_1.statecodename,
FilteredInvoice_1.totalamount_base,
FilteredMag_Payment.mag_paymentdate,
FilteredMag_Payment.mag_amount_base,
GETDATE() AS Today
FROM FilteredAccount AS CRMAF_FilteredAccount
LEFT JOIN FilteredInvoice AS FilteredInvoice_1 ON FilteredInvoice_1.accountid = CRMAF_FilteredAccount.accountid
JOIN FilteredMag_Payment ON FilteredInvoice_1.invoiceid = FilteredMag_Payment.mag_invoiceid
WHERE (FilteredInvoice_1.statecodename <> 'Canceled')
These alone do exactly what i am wanting them to but as soon as i try and join them using a "UNION" or "Sub-query" the second query always breaks and displays the wrong information.
Am I just being blond not being able to work this out or am I actually doing something wrong.
All help is appreciated.
Many thanks Simon.
EDIT:
What I mean by "Wrong information" is that the 2nd query is returning all values rather then following the CRMAF_ prefix and returning only values from the account it is run on.
It's hard to guess what do you mean by "wrong information" but I believe you want UNION ALL rather than UNION.
UNION removes duplicates so the records from the second query won't be returned if they were previously returned by the first query. In addition, the possible duplicates within one query will be eliminated too.
The number of records in a UNION can be less than the total count of records in two queries.
If you just want to concatenate two recordsets, use UNION ALL:
SELECT FilteredInvoice.accountidname,
FilteredInvoice.createdon,
FilteredInvoice.createdon AS sort_date,
FilteredInvoice.duedate,
FilteredInvoice.invoicenumber,
FilteredInvoice.statecodename,
FilteredInvoice.totalamount_base,
CONVERT(datetime, NULL) AS mag_paymentdate,
0 AS mag_amount_base,
GETDATE() AS Today
FROM FilteredAccount AS CRMAF_FilteredAccount
JOIN FilteredInvoice ON FilteredInvoice.accountid = CRMAF_FilteredAccount.accountid
JOIN FilteredMag_Payment ON FilteredInvoice.invoiceid = FilteredMag_Payment.mag_invoiceid
WHERE (FilteredInvoice.statecodename <> 'Canceled')
UNION ALL
SELECT FilteredInvoice_1.accountidname,
FilteredInvoice_1.createdon,
FilteredInvoice_1.createdon AS sort_date,
FilteredInvoice_1.duedate,
FilteredInvoice_1.invoicenumber,
FilteredInvoice_1.statecodename,
FilteredInvoice_1.totalamount_base,
FilteredMag_Payment.mag_paymentdate,
FilteredMag_Payment.mag_amount_base,
GETDATE() AS Today
FROM FilteredAccount AS CRMAF_FilteredAccount
LEFT JOIN FilteredInvoice AS FilteredInvoice_1 ON FilteredInvoice_1.accountid = CRMAF_FilteredAccount.accountid
JOIN FilteredMag_Payment ON FilteredInvoice_1.invoiceid = FilteredMag_Payment.mag_invoiceid
WHERE (FilteredInvoice_1.statecodename <> 'Canceled')
It looks to me as though you should be able to get the same results as you would from the UNIONed query, with the following:
SELECT FilteredInvoice_1.accountidname,
FilteredInvoice_1.createdon,
FilteredInvoice_1.createdon AS sort_date,
FilteredInvoice_1.duedate,
FilteredInvoice_1.invoicenumber,
FilteredInvoice_1.statecodename,
FilteredInvoice_1.totalamount_base,
CASE PF.pay_flag
WHEN 0.0 THEN CONVERT(datetime, NULL)
ELSE FilteredMag_Payment.mag_paymentdate
END AS mag_paymentdate,
FilteredMag_Payment.mag_amount_base * PF.pay_flag AS mag_amount_base,
GETDATE() AS Today
FROM FilteredAccount AS CRMAF_FilteredAccount
CROSS JOIN (SELECT 1.0 pay_flag UNION SELECT 0.0) AS PF
JOIN FilteredInvoice AS FilteredInvoice_1 ON FilteredInvoice_1.accountid = CRMAF_FilteredAccount.accountid
LEFT JOIN FilteredMag_Payment ON FilteredInvoice_1.invoiceid = FilteredMag_Payment.mag_invoiceid
WHERE (FilteredInvoice_1.statecodename <> 'Canceled') AND
(PF.pay_flag = 0 OR FilteredMag_Payment.mag_invoiceid IS NOT NULL)
EDIT: LEFT JOIN FilteredMag_Payment
FURTHER EDIT: added final parenthesised OR condition to WHERE clause.