Converting/concatenating individual bytes from a VARCHAR into a BIGINT using T-SQL - tsql

Working between two database systems, I need to convert a VARCHAR identifier into a BIGINT. My VARCHAR is always of the form "###-XXX-XXX-###" where # is any digit, and X is any alpha-numeric character (e.g. "103-AF7-GGB-005"). The two ### entries are guaranteed to be below 256, so I want to store each of those in a single byte of the BIGINT (the first and last bytes respectively), with each of the 6 other characters stored as a byte each.
I've implemented this outside of the database, and it solves the problem I needed it to, but now I have the need to create the function in t-sql and I have not been able to figure out how to do this.
Thanks in advance for the help!

You could do this:
DECLARE #inp VARCHAR(100) = '223-ABC-DEF-234'
, #BITS BIGINT;
SELECT #BITS =
CASE
WHEN CONVERT(BIGINT, LEFT(#inp, 3)) > 127
THEN (CONVERT(BIGINT, LEFT(#inp, 3))-128) * POWER(CONVERT(BIGINT, 2), 56)
-9223372036854775808
ELSE CONVERT(BIGINT, LEFT(#inp, 3)) * POWER(CONVERT(BIGINT, 2), 56)
END
+ CONVERT(BIGINT, ASCII(substring(#inp, 5, 1))) * POWER(CONVERT(BIGINT, 2), 48)
+ CONVERT(BIGINT, ASCII(substring(#inp, 6, 1))) * POWER(CONVERT(BIGINT, 2), 40)
+ CONVERT(BIGINT, ASCII(substring(#inp, 7, 1))) * POWER(CONVERT(BIGINT, 2), 32)
+ CONVERT(BIGINT, ASCII(substring(#inp, 9, 1))) * POWER(CONVERT(BIGINT, 2), 24)
+ CONVERT(BIGINT, ASCII(substring(#inp, 10, 1))) * POWER(CONVERT(BIGINT, 2), 16)
+ CONVERT(BIGINT, ASCII(substring(#inp, 11, 1))) * POWER(CONVERT(BIGINT, 2), 8)
+ CONVERT(BIGINT, RIGHT(#INP, 3));
select CONVERT(binary(8), #bits);
-- Returns 0xDF414243444546EA
SELECT CONVERT(VARCHAR, CONVERT(INT, 0XDF))
+ '-' + CHAR(0X41)
+ CHAR(0X42)
+ CHAR(0X43)
+ '-' + CHAR(0X44)
+ CHAR(0X45)
+ CHAR(0X46)
+ '-' + CONVERT(VARCHAR, CONVERT(INT, 0XEA));
-- Returns 223-ABC-DEF-234: our original string
The big subtraction is to flip the sign bit. You're using all 64 bits if the first number is more than 127. Just multiplying by 2^56 will overflow the data type, since BIGINT is signed.

Related

postgresql syntax error using DAY as date

I can't identify the syntax mistake on this query, where´s the syntax mistake?
SELECT A.WPAN8, A.WPSRP1, A.WPBP01, A.WPSLSM, A.WP55QTA1, A.WPCENTYR,
A.WPAAN01, A.WPAAN02, A.WPAAN03, A.WPAAN04, A.WPAAN05, A.WPAAN06,
A.WPAAN07, A.WPAAN08, A.WPAAN09, A.WPAAN10, A.WPAAN11, A.WPAAN12,
cast(((((((cast(cast(((WPUPMJ / 1000) + 1900) as decimal (4,0)) as
char(4)) || '-01-01 ') || substring(cast(cast((WPUPMT + 1000000) as
decimal (7,0)) as char(7)) from 2 for 2)) || ':') ||
substring(cast(cast((WPUPMT + 1000000) as decimal (7,0)) as char(7)) from
4 for 2)) || ':') || substring(cast(cast((WPUPMT + 1000000) as decimal
(7,0)) as char(7)) from 6 for 2)) as timestamp)+
ceiling(cast(substring(cast(cast(((WPUPMJ + 1900000) - 1) as decimal (7))
as character (7)) from 5 for 3) as decimal (3)))DAY as maxdate FROM
CRPDTA.F5742001 A where cast(((((((cast(cast(((WPUPMJ / 1000) + 1900) as
decimal (4,0)) as char(4)) || '-01-01 ') || substring(cast(cast((WPUPMT +
1000000) as decimal (7,0)) as char(7)) from 2 for 2)) || ':') ||
substring(cast(cast((WPUPMT + 1000000) as decimal (7,0)) as char(7)) from
4 for 2)) || ':') || substring(cast(cast((WPUPMT + 1000000) as decimal
(7,0)) as char(7)) from 6 for 2)) as timestamp)+
ceiling(cast(substring(cast(cast(((WPUPMJ + 1900000) - 1) as decimal (7))
as character (7)) from 5 for 3) as decimal (3)))DAY > '2000-01-01
00:00:00.000000';
It is saying ERROR: syntax error at or near "DAY"
postgresql uses a slightly different interval syntax to that.
I think you want * '1 day'::interval instead of DAY

SQL Server 2008 R2 - convert all datetime parts (as ints) into a datetime column

I have a table that has the datetime pieces (year, month, day, hour, minute, second, millisecond) stored as integers. I'd like to concatenate them into a single datetime column.
I've tried various approaches but none work - there seems to be no simple way to put these items together?
You can convert each part to a varchar and concatenate them together in the format of an ISO datetime string. Then use Convert to convert the string to a DateTime.
Here is an example. You would need to replace each hard coded integer with the name of the column from your table.
SELECT CONVERT(DATETIME, CAST(2016 AS VARCHAR(4)) -- year
+ '-' + CAST('0' + CAST(8 AS VARCHAR(2)) AS VARCHAR(2)) -- month
+ '-' + RIGHT('0' + CAST(13 AS VARCHAR(2)), 2) -- day of month
+ 'T' + RIGHT('0' + CAST(16 AS VARCHAR(2)), 2) -- hours (I assume its military time (24 hours))
+ ':' + RIGHT('0' + CAST(32 AS VARCHAR(2)), 2) -- minutes
+ ':' + RIGHT('0' + CAST(07 AS VARCHAR(2)), 2) -- seconds
+ '.' + RIGHT('000' + CAST(64 AS VARCHAR(3)), 3)) AS MyDate -- milliseconds
FROM yourTable
Or with column names (assumed)
SELECT CONVERT(DATETIME, CAST(yt.Year AS VARCHAR(4)) -- year
+ '-' + CAST('0' + CAST(yt.Month AS VARCHAR(2)) AS VARCHAR(2)) -- month
+ '-' + RIGHT('0' + CAST(yt.Day AS VARCHAR(2)), 2) -- day of month
+ 'T' + RIGHT('0' + CAST(yt.Hours AS VARCHAR(2)), 2) -- hours (I assume its military time (24 hours))
+ ':' + RIGHT('0' + CAST(yt.Minutes AS VARCHAR(2)), 2) -- minutes
+ ':' + RIGHT('0' + CAST(yt.Seconds AS VARCHAR(2)), 2) -- seconds
+ '.' + RIGHT('000' + CAST(yt.Milliseconds AS VARCHAR(3)), 3)) AS MyDate -- milliseconds
FROM yourTable yt
One more note. Microsoft recommends that you use DateTime2 instead of DateTime to persist date time values starting with Sql Server 2008 (which you tagged in your question).
Prior to sql server 2012, you can use a series of nested DATEADD() functions to mimic DATETIMEFROMPARTS() function
Create and populate sample data (In your next question, please save us this step)
DECLARE #T as table
(
cYear int,
cMonth int,
cDay int,
cHour int,
cMinute int,
cSecond int,
cMillisecond int
)
INSERT INTO #T VALUES(2016, 6, 22, 16, 34, 25, 3)
The query:
SELECT *,
DATEADD(MILLISECOND, cMillisecond,
DATEADD(SECOND, cSecond,
DATEADD(MINUTE, cMinute,
DATEADD(HOUR, cHour,
DATEADD(DAY, cDay -1,
DATEADD(MONTH, cMonth - 1,
DATEADD(YEAR, cYear - 2000, '2000-01-01')
)
)
)
)
)
) As TheDate
FROM #T
Results:
cYear cMonth cDay cHour cMinute cSecond cMillisecond TheDate
----- ------ ---- ----- ------- ------- ------------- -----------------------
2016 6 22 16 34 25 3 2016-06-22 16:34:25.003
Note that the base date I'm using is January 1st 2000, therefor you need to subtract 2000 from the year, 1 from the month and 1 from the days.

Convert a Date to Julian Date and then Store in a Numeric Field in SQL Server 2005

I have a date field in a T-SQL variable which I want to convert to Julian Date Format and then insert in to a Numeric column in a table. Can someone please help?
I saw there are some posts on Julian Date but I am not able to get through.
EX :
declare #d datetime
Set #d = GetDate()
select datediff(d, 0, #d) + 693596
The above statement does convert in to a julian date but not in the correct format. For example if today is 15 Feb 2014 then this should convert this in to 114046 but it converts this to 735279.
Also once this gets converted to correct julian format. I want to convert this to Numeric as I want to insert to a numeric column in a table.
I am sorry if this question has been asked previously. I am new to SQL Server 2005.
Any help will be appreciated
Regards
Give this a go:
DECLARE #input_date DATETIME
SELECT #input_date = getdate()
SELECT datepart(year, #input_date) * 1000 + datepart(dy, #input_date)
The above answer doesn't seem to work for me.
--If Julian Format is defined as CYYJJJ where:
-- C is the number of centuries since 1900-01-01
-- YY is the 2 digit year
-- JJJ is the day number of the given YY year
--Convert Date => Julian uning CYYJJJ
declare #date datetime = '02/15/2014'
select (datepart(year, #date)-1900)*1000 + datepart(dy, #date)
--output: 114046
--Convert Julian => Date using CYYJJJ
declare #jdate int = 114046
select dateadd(dd, (#jdate - ((#jdate/1000) * 1000)) - 1, dateadd(yy, #jdate/1000 - 1900, 0))
--output: '02/15/2014'
---
--Convert Date => Julian uning YYYYJJJ
declare #dateB datetime = '02/15/2014'
select (datepart(year, #dateB))*1000 + datepart(dy, #dateB)
--output: 114046
--Convert Julian => Date using YYYYJJJ
declare #jdateB int = 2014046
select dateadd(dd, (#jdateB - ((#jdateB/1000) * 1000)) - 1, dateadd(yy, #jdateB/1000 - 1900, 0))
--output: '02/15/2014'
I would suggest putting that into a Scalar Function so you can execute it like:
select dbo.FromJulianDate(2014046)
sourced from http://www.sqlservercentral.com/Forums/Topic778671-169-1.aspx
The following will give an 7 character julian date output of: YYYYDDD
SELECT datepart(year, #input_date) * 1000 + datepart(dy, #input_date)
The following will give an 6 character julian date output output of: CYYDDD
SELECT CONCAT((DATEPART(year, #input_date) -1900),(DATEPART(dy, #input_date)))
Further explanation
Julian dates start from 1900-01-01
The C element is the century from 1900.
If the year is 1950, the C part will be 0
If the year is 2000, the C part will be 1 (and this increases with each 100 years)
The DDD element reflects the number of days from the beginning of the
year so 28th February will be 058
This should do what you are looking for:
SELECT CONCAT((DATEPART(year, #date) -1900),(DATEPART(dy, #date)))
This should work:
DECLARE #date DATETIME;
SET #date = '2014-2-15';
SELECT #date,
YEAR(#date),
DATEPART(DAYOFYEAR, #date),
(YEAR(#date) - 1900) * 1000 + DATEPART(DAYOFYEAR, #date) JulianDate;
I have somewhat of a simpler answer that I came up with..
You can edit what you want to display, with some simple replacing.
The query looks like this:
DECLARE #t_stamp datetime = GETDATE()
DECLARE #year char(4) = RIGHT(DATEPART(year, #t_stamp),1)
DECLARE #jday char(4) = RIGHT('000'+CAST(DATEPART(DAYOFYEAR, #t_stamp) AS varchar(3)),3)
SELECT RTRIM(#year) + #jday
Breakdown
Start off by declaring your starting datetime
DECLARE #t_stamp datetime = GETDATE()
Then set the year - starts from right to left
DECLARE #year char(4) = RIGHT(DATEPART(year, #t_stamp),1)
--Changing '1' to '2' will give me 22 otherwise just 2.
then set your julian day (3 digits)
DECLARE #jday char(4) = RIGHT('000'+CAST(DATEPART(DAYOFYEAR, #t_stamp) AS varchar(3)),3)
Finally do your SELECT statement - you can append anything to this to make it unique or just cast it as an int.
SELECT 'SB-' + RTRIM(#year) + #jday
Your Result (Today's date 1/25/2022)
SB-2025
(Since this is the highest ranked result in google) . . .
In case you need to turn this into an expression statement in a SSIS package, you can use this
(DT_WSTR, 50)(((YEAR(GETDATE())-1900)*1000)+DATEPART("dy", GETDATE()))
For example:
"SELECT somefield FROM " + #[User::FileHeaderTable] + " WHERE JdeDate = "+ (DT_WSTR, 50)(((YEAR(GETDATE())-1900)*1000)+DATEPART("dy", GETDATE()))
Utilizing the known values here are two solutions I have personally utilized which I first did in NodeJS then converted to MSSQL when trying to get Julian Microsecond.
I had a known value in Gregorian and Julian Microsecond and so I just had to convert bridge the two and used https://www.aavso.org/jd-calculator as a check along the way. I used this answer to
/* Known Values:
Gregorian: 2021-03-03 21:55:00.000
Julian; 2459277.41319 )
JulianMicrosecond: 212481593700000000
*/
I used this answer along the way to develop my Nodejs code.
let getJulainDay = (Year,Month,Day) => {
a = parseInt((14 - Month) / 12);
y = Year + 4800 - a;
m = Month + 12 * a - 3;
JDN =
(Day +
parseInt(
(
(153 * m + 2) / 5) +
(365 * y) +
parseInt(y / 4) -
parseInt(y / 100) +
parseInt(y / 400) -
32045 )
)
//Into Julian Microseconds 24*60*60*1e6
* 24 * 60 * 60 * 1000000;
return JDNMicroSeconds;
};
Then I mapped this into MSSQL that I had to treat a bit differently, noting that I had to enter all integer values in the formula above as floats or I would have had to cast each result.. it was just easier to enter them as floats.. if I don't do this I only get integer results and it throws the results off by years.
This is definitely an overly verbose breakdown but it allows you to see the steps along the way.
DECLARE #date DATETIME;
SET #date = '2021-03-03 21:55:00.000';
SELECT #date,
YEAR(#date) as Year,
DATEPART(MONTH,#date) as Month,
DATEPART(DAY,#date) as Day,
DATEPART(DAYOFYEAR, #date) as DofY,
14 -(DATEPART(MONTH, #date)) as mm,
((14.0 -(DATEPART(MONTH, #date))) / 12.0) as A,
(YEAR(#date) + 4800.0 - ((14.0 -(DATEPART(MONTH, #date))) / 12.0)) as Y,
( DATEPART(MONTH,#date) + (12.0 * ((14.0 -(DATEPART(MONTH, #date))) / 12.0)) -3.0) as M,
/* Watch the order of operations/parethesis! */
(DATEPART(DAY,#date) +
((153.0 * (( DATEPART(MONTH,#date) + (12.0 * ((14.0 -(DATEPART(MONTH, #date))) / 12.0)) -3.0)) + 2.0) / 5.0) +
(365.0 * ((YEAR(#date) + 4800.0 - ((14.0 -(DATEPART(MONTH, #date))) / 12.0)))) +
((YEAR(#date) + 4800.0 - ((14.0 -(DATEPART(MONTH, #date))) / 12.0)) / 4.0) -
((YEAR(#date) + 4800.0 - ((14.0 -(DATEPART(MONTH, #date))) / 12.0)) / 100.0) +
((YEAR(#date) + 4800.0 - ((14.0 -(DATEPART(MONTH, #date))) / 12.0)) / 400.0) -
32045.0) as JDN,
(DATEPART(DAY,#date) +
((153.0 * (( DATEPART(MONTH,#date) + (12.0 * ((14.0 -(DATEPART(MONTH, #date))) / 12.0)) -3.0)) + 2.0) / 5.0) +
(365.0 * ((YEAR(#date) + 4800.0 - ((14.0 -(DATEPART(MONTH, #date))) / 12.0)))) +
((YEAR(#date) + 4800.0 - ((14.0 -(DATEPART(MONTH, #date))) / 12.0)) / 4.0) -
((YEAR(#date) + 4800.0 - ((14.0 -(DATEPART(MONTH, #date))) / 12.0)) / 100.0) +
((YEAR(#date) + 4800.0 - ((14.0 -(DATEPART(MONTH, #date))) / 12.0)) / 400.0) -
32045.0) * 24 * 60 * 60 * 1000000 as JDNMicroSecond,
/* What others proposed which I do not believe is correct. */
(YEAR(#date) - 1900) * 1000 + DATEPART(DAYOFYEAR, #date) IncorrectJDN;
The output being:

Loosing the battle - Datediff working but I want to apply a condition

I know I'm gonna 'kick myself' when I see the answer but right now I can't see it.
SELECT [faxdate]
,DATEDIFF(day,
CAST(SUBSTRING(RPT.FaxDate, 1, 4) + '-' + SUBSTRING(RPT.FaxDate, 5, 2) + '-' + SUBSTRING(RPT.FaxDate, 7, 2) AS DATE), getdate()) AS vDiff
faxdate vDiff 20130704 62 20130705 61
20130705 61 20130708 58
Works great, but I want to be able to test the number of days Eg. records over 60 days.
When I add this :
WHERE (DATEDIFF(day,
CAST(SUBSTRING(RPT.FaxDate, 1, 4) + '-' + SUBSTRING(RPT.FaxDate, 5, 2) + '-' + SUBSTRING(RPT.FaxDate, 7, 2) AS DATE), getdate()) >60)
I get: Conversion failed when converting date and/or time from character string.
I have also tried this sql as a derived table and then tested vDiff ....i'm obviously not doing it right
any help would be appreciated
ttfn
Martyn
(Cornwall England and it's not raining .. result !)
Try
SELECT [faxdate],DAY(DATEDIFF(CAST(SUBSTRING(RPT.FaxDate, 1, 4) + '-' +
SUBSTRING(RPT.FaxDate, 5, 2) + '-' + SUBSTRING(RPT.FaxDate, 7, 2) AS DATE),
getdate())) AS vDiff
instead of using where, use having like below
HAVING vDiff > 60

How to convert a Cursor into SELECT queries?

I am using SSRS 2008 and i have a stored proc which currently uses cursors to delete and add data, but even after I convert this to select queries, I am getting error:
Msg 102, Level 15, State 1, Line 39
Incorrect syntax near ')'.
Here was the original Cursor which worked:
OPEN PARTS
FETCH PARTS INTO #PART_NUM,
#PART_DESC
SET #PARTS_FETCH = ##FETCH_STATUS
WHILE #PARTS_FETCH = 0 BEGIN
SET #THE_DATE = dateadd("yy", -1, dateadd("m", -1, getdate()))
SET #END_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, getdate()) + 1, 0))
-- Get PL for part number
Delete from #tbl_PL
Insert #tbl_PL
SELECT FRUD.tblXref.product_code FROM FRUD.tblfieldOrderablePart INNER JOIN
FRUD.MAX_APPROVED ON FRUD.tblfieldOrderablePart.fop_no = FRUD.MAX_APPROVED.fop_no AND
FRUD.tblfieldOrderablePart.fop_revision = FRUD.MAX_APPROVED.MaxOffop_revision INNER JOIN
FRUD.tblXref ON FRUD.MAX_APPROVED.fop_no = FRUD.tblXref.fop_no AND
FRUD.MAX_APPROVED.MaxOffop_revision = FRUD.tblXref.fop_revision
WHERE (dbo.FORMAT_PART(FRUD.tblfieldOrderablePart.fop_no) = dbo.FORMAT_PART(#PART_NUM))
-- End Get PL
WHILE #THE_DATE <= #END_DATE BEGIN
SET #THE_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, #THE_DATE) + 1, 0))
-- Get census using PL
SELECT #ALL_TOTAL = SUM(TheSum) FROM (SELECT CAST(RELIABILITY.Census.Census AS DECIMAL(9,2)) AS TheSum, (CONVERT(datetime, LEFT(CONVERT(char, Period), 4) + '-' + RIGHT(Period, 2) + '-1', 102)) as ThePeriod
FROM RELIABILITY.Census
WHERE RELIABILITY.Census.PL In (Select distinct * FROM #tbl_PL)
AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4) + '-' + RIGHT(Period, 2) + '-1', 102) >=
DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0)) AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4)
+ '-' + RIGHT(Period, 2) + '-1', 102) <= #THE_DATE) UNION ALL SELECT CAST(Census AS DECIMAL(9,2)) AS TheSum, Period FROM [MANUAL].SMARTSOLVE_CENSUS WHERE (Period >= DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0) AND Period <= #THE_DATE) AND (PL In (Select distinct * FROM #tbl_PL)))A
And here is my conversion to Select:
DECLARE #THE_DATE datetime,
#END_DATE datetime,
#THE_GOAL decimal(18,2),
#PART_NUM nvarchar(50),
#UNCHANGED_PART_NUM nvarchar(50),
#PART_DESC varchar(35),
#PARTS_FETCH int,
#NUM_FAILED int,
#AVG_CENSUS decimal(18,2),
#PL_VAR nvarchar(50),
#PL_FETCH int,
#PL_TOTAL decimal(9,2),
#ALL_TOTAL decimal(9,2)
--WHILE #PARTS_FETCH = 0 BEGIN
SET #THE_DATE = dateadd("yy", -1, dateadd("m", -1, getdate()))
SET #END_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, getdate()) + 1, 0))
--WHILE #THE_DATE <= #END_DATE BEGIN
SET #THE_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, #THE_DATE) + 1, 0))
-- Get census using PL
SELECT #ALL_TOTAL = SUM(TheSum) FROM
(SELECT CAST(RELIABILITY.Census.Census AS DECIMAL(9,2)) AS TheSum
from RELIABILITY.Census
WHERE RELIABILITY.Census.PL In (Select distinct * FROM #tbl_PL)
AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4) + '-' + RIGHT(Period, 2) + '-1', 102) >=
DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0)) AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4)+ '-' + RIGHT(Period, 2) + '-1', 102) <= #THE_DATE)
UNION ALL
SELECT CAST(Census AS DECIMAL(9,2)) AS TheSum, Period
FROM [MANUAL].SMARTSOLVE_CENSUS
WHERE (Period >= DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0) AND Period <= #THE_DATE) AND (PL In (Select distinct * FROM #tbl_PL))
))A
As Joel and Lamak pointed out you have an extra ) This is actually really easy to find if you use something like Instant SQL formatter This will give the error
)(11,3) expected token:Unknown
)(11,3) expected token:
It also formats the SQL as below which makes it a little easier to follow.
SELECT #ALL_TOTAL = SUM(thesum)
FROM (SELECT CAST(reliability.census.census AS DECIMAL(9, 2)) AS thesum
FROM reliability.census
WHERE reliability.census.pl IN (SELECT DISTINCT *
FROM #tbl_pl)
AND ( CONVERT(DATETIME, LEFT(CONVERT(CHAR, period), 4) + '-' +
RIGHT(
period, 2)
+
'-1'
, 102) >= Dateadd(mm, Datediff(mm, 0, #THE_DATE) - 5, 0) )
AND ( CONVERT(DATETIME, LEFT(CONVERT(CHAR, period), 4)+ '-' +
RIGHT(
period, 2) +
'-1',
102) <= #THE_DATE )
UNION ALL
SELECT CAST(census AS DECIMAL(9, 2)) AS thesum,
period
FROM [MANUAL].smartsolve_census
WHERE ( period >= Dateadd(mm, Datediff(mm, 0, #THE_DATE) - 5, 0)
AND period <= #THE_DATE )
AND ( pl IN (SELECT DISTINCT *
FROM #tbl_pl) ))a
Sounds like you have mis-matched parentheses, double check and make sure they all line up correctly. You have one more ")" at the end of that last select statement than you have ever being opened. That's a lot of nesting! Make sure everything matches up how you intended, or you may get unexpected results if your UNION gets applied at the wrong level or something.
If I'm reading your query correctly, you have two errors. The first is an extra ")" on the last line, it should be:
WHERE (Period >= DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0) AND Period <= #THE_DATE) AND (PL In (Select distinct * FROM #tbl_PL))
) A
And, I think you also have more columns on your query after the UNION ALL, you are selecting CAST(Census AS DECIMAL(9,2)) AS TheSum, Period and on the first one you are selecting only one column: CAST(RELIABILITY.Census.Census AS DECIMAL(9,2)) AS TheSum