How do I get query to give me results of month using url? - coldfusion

The query below works and gets me the correct results.
<cfset month = URL.month>
<cfset year = URL.year>
<cfquery datasource="testing_1" name="allDepartments">
SELECT CAST(employeedept AS INT) as dept,
ROUND(AVG(case when rating1>0 THEN CAST(rating1 AS FLOAT) ELSE null END), 2) as q1,
ROUND(AVG(case when rating2>0 THEN CAST(rating2 AS FLOAT) ELSE null END), 2) as q2,
ROUND(AVG(case when rating3>0 THEN CAST(rating3 AS FLOAT) ELSE null END), 2) as q3,
ROUND(AVG(case when rating4>0 THEN CAST(rating4 AS FLOAT) ELSE null END), 2) as q4,
ROUND(AVG(case when rating5>0 THEN CAST(rating5 AS FLOAT) ELSE null END), 2) as q5
FROM CSEReduxResponses
WHERE execoffice_date BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0)
AND DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1)
AND execoffice_status = 1
group by employeedept
order by employeedept
</cfquery>
I want to get the execoffice_date to give me the data for a month ago, which is why I'm
using GETDATE. But if the url changes month=5&year=2014 to month=3&year=2014 it will give me the
same results in the query the same time.
What I would like to get the query to get the data depending on the url month and year.
How would I accomplish this?

If you are given url.year and url.month, this will get you the current month.
StartDate = CreateDate(url.year, url.month, 1);
EndDate = DateAdd("m", 1, StartDate); // you really do want the 1st of next month
Use them like this:
and execoffice_date >= <cfqueryparam cfsqltype="cf_sql_date" value="#StartDate#">
and execoffice_date < <cfqueryparam cfsqltype="cf_sql_date" value="#EndDate#">
For previous months, use date add on those variables.

Related

PowerBI Create List of Month Dates

Hi in powerbi I am trying to create a list of dates starting from a column in my table [COD], and then ending on a set date. Right now this is just looping through 60 months from the column start date [COD]. Can i specify an ending variable for it loop until?
List.Transform({0..60}, (x) =>
Date.AddMonths(
(Date.StartOfMonth([COD])), x))
Assuming
start=Date.StartOfMonth([COD]),
end = #date(2020,4,30),
One way is to add column, custom column with formula
= { Number.From(start) .. Number.From(end) }
then expand and convert to date format
or you could generate a list with List.Dates instead, and expand that
= List.Dates(start, Number.From(end) - Number.From(start)+1, #duration(1, 0, 0, 0))
Assuming you want start of month dates through June 2023. In the example below, I have 2023 and 6 hard coded, but this could easily come from a parameter Date.Year(DateParameter) or or column Date.Month([EndDate]).
Get the count of months with this:
12 * (2023 - Date.Year([COD]) )
+ (6 - Date.Month([COD]) )
+ 1
Then just use this column in your formula:
List.Transform({0..[Month count]-1}, (x) =>
Date.AddMonths(Date.StartOfMonth([COD]), x)
)
You could also combine it all into one harder to read formula:
List.Transform(
{0..
(12 * ( Date.Year(DateParameter) - Date.Year([COD]) )
+ ( Date.Month(DateParameter) - Date.Month([COD]) )
)
}, (x) => Date.AddMonths(Date.StartOfMonth([COD]), x)
)
If there is a chance that COD could be after the End Date, you would want to include error checking the the Month count formula.
Generate list:
let
Start = Date1
, End = Date2
, Mos = ElapsedMonths(End, Start) + 1
, Dates = List.Transform(List.Numbers(0,Mos), each Date.AddMonths(Start, _))
in
Dates
ElapsedMonths(D1, D2) function def:
(D1 as date, D2 as date) =>
let
DStart = if D1 < D2 then D1 else D2
, DEnd = if D1 < D2 then D2 else D1
, Elapsed = (12*(Date.Year(DEnd)-Date.Year(DStart))+(Date.Month(DEnd)-Date.Month(DStart)))
in
Elapsed
Of course, you can create a function rather than hard code startdate and enddate:
(StartDate as date, optional EndDate as date, optional Months as number)=>
let
Mos = if EndDate = null
then (if Months = null
then error Error.Record("Missing Parameter", "Specify either [EndDate] or [Months]", "Both are null")
else Months
)
else ElapsedMonths(StartDate, EndDate) + 1
, Dates = List.Transform(List.Numbers(0, Mos), each Date.AddMonths(StartDate, _))
in
Dates

Coldfusion Dynamic Variable (?) parsed to SQL Query

This is the first time I am attempting to parse a variable to a CF query, but I have run into a few little issues.
In summary, I am creating a pivot table of sales by operators by week. Manually, no hassle, but I only want a subset of weeks, not all. Again, no real problem if I want hardcoded weeks, but the problem comes in when I try and parse a week number to the SQL query to create the subset of dynamic weeks.
The CFDUMP shows me that the query is executing based on what I am sending to it, but when it comes to outputting the value of the field (the week), it takes the variable name value, and not the field value if that makes sense?
I know that I shouldn't be having field names as values, but I still tryingh to test right now. With the manual query, I prefix the week number with a 'W' e.g. W9, but when I try and do that I get
MANUAL QUERY
SELECT UserName,
ISNULL([W6], 0) AS [W6],
ISNULL([W7], 0) AS [W7],
ISNULL([W8], 0) AS [W8],
ISNULL([W9], 0) AS [W9],
ISNULL([W10], 0) AS [W10]
FROM ( SELECT CASE
WHEN SUBSTRING(Username, 1, 3) = 'd.S' THEN 'DS'
WHEN SUBSTRING(Username, 1, 3) = 'p.R' THEN 'PR'
WHEN SUBSTRING(Username, 1, 3) = 'j.G' THEN 'JG'
WHEN SUBSTRING(Username, 1, 3) = 'b.c' THEN 'BC'
ELSE 'Other' END AS Username,
CONCAT('W', DATEPART(isowk, ERCFullAuditDate)) as XWeek,
COUNT(1) [SalesCount]
FROM [ERC-Transactions].[dbo].[ERC-Audit]
WHERE ( ERCModule = 'Carriage Return on Account'
AND ERCFullAuditDate >= DATEADD(week, -4, GETDATE())
OR ( ERCFullAuditDate <= DATEADD(week, -52, convert(datetime, GETDATE()))
and ERCFullAuditDate >= DATEADD(week, -56, convert(datetime, GETDATE()))))
GROUP BY DATEPART(isowk, ERCFullAuditDate),
UserName) ST
PIVOT ( SUM(SalesCount)
for XWeek in ([W6], [W7], [W8], [W9], [W10])) as StorePivot
The above yields this result.
THE COLDFUSION DYNAMIC QUERY
Now when I try and do the same, but by parsing variables to the query, the CFDUMP yields the correct values, but as I said, when I try and output this, I get the field name and not the value.
To be honest, I have two issues here in that I need to address. The variable field name, but also when I come to adding the concatenation of 'W' to the week number, I am seeing an 'Error converting data type nvarchar to int.' I think I may need a cfqueryparam, but I am not sure.
<cfset WEEK_2 = DATETImeFormat(DateAdd("ww",-2,now()),"w")>
<cfoutput>Week: #WEEK_2#</cfoutput> (This is the value of the WEEK_2 variable)<br>
<cfset XX = "">
<cfset XX = XX & "SELECT UserName, ">
<cfset XX = XX & "ISNULL([#WEEK_2#], 0) AS [#WEEK_2#] ">
<cfset XX = XX & "FROM ( SELECT CASE ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'd.S' THEN 'DS' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'p.R' THEN 'PR' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'j.G' THEN 'JG' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'b.c' THEN 'BC' ">
<cfset XX = XX & "ELSE 'Other' END AS Username, ">
<cfset XX = XX & "DATEPART(isowk, ERCFullAuditDate) as XWeek, ">
<cfset XX = XX & "COUNT(1) [SalesCount] ">
<cfset XX = XX & "FROM [EBS-ERC-Transactions].[dbo].[ERC-Audit] ">
<cfset XX = XX & "WHERE ( ERCModule = 'Carriage Return on Account' ">
<cfset XX = XX & "AND ERCFullAuditDate >= DATEADD(week, -4, GETDATE()) ">
<cfset XX = XX & "OR ( ERCFullAuditDate <= DATEADD(week, -52, convert(datetime, GETDATE())) ">
<cfset XX = XX & "and ERCFullAuditDate >= DATEADD(week, -56, convert(datetime, GETDATE())))) ">
<cfset XX = XX & "GROUP BY DATEPART(isowk, ERCFullAuditDate), ">
<cfset XX = XX & "UserName) ST ">
<cfset XX = XX & "PIVOT ( SUM(SalesCount) ">
<cfset XX = XX & "for XWeek in ([#WEEK_2#])) as StorePivot ">
<cfquery name = "QueryTest" dataSource = "EBSERC">
#PreserveSingleQuotes(XX)#
</cfquery>
<br>
<cfoutput Query="QueryTest">
#UserName#, #WEEK_2#<br>
</cfoutput>
<br>
<cfdump var="#QueryTest#" />
And this is the result ...
Ultimately, as mentioned before, I want to concatenate 'W' to the week number field.
Any guidance or a steer in the right direction will be VERY appreciated and thanks for your time.
Thank you very much for reading.
This is too long for comments.
Since the column labels are dynamic and closely bound to the database, I'd probably do this all on the database side. Preferably inside a stored procedure.
If you're using SQL Server 2017+, a CTE could be used to generate the weeks within the desired date range. Then STRING_AGG() used to convert the results into comma separated lists.
; WITH dates AS (
-- Generate range between -56 and -52 weeks ago
SELECT DateAdd(wk, -56, GETDATE()) AS WeekDate
UNION ALL
SELECT DateAdd(wk, 1, WeekDate)
FROM dates
WHERE DateAdd(wk, 1, WeekDate) <= DateAdd(wk, -52, GETDATE())
)
, dateLabels AS (
-- extract week number and construct label "W1","W2",etc..
SELECT DATEPART(isowk, WeekDate) AS WeekNum
, QUOTENAME( CONCAT('W', DATEPART(isowk, WeekDate) )) AS WeekLabel
FROM dates
)
-- convert to comma separated lists
SELECT STRING_AGG( WeekLabel, ',')
WITHIN GROUP (ORDER BY WeekNum) AS PivotColumns
, STRING_AGG( CONCAT('ISNULL(', WeekLabel, ',0) AS ', WeekLabel ), ',')
WITHIN GROUP (ORDER BY WeekNum) AS SelectColumns
FROM dateLabels
;
The results would look like this (minus any line wrapping)
PivotColumns
SelectColumns
[W6],[W7],[W8],[W9],[W10]
ISNULL([W6],0) AS [W6],ISNULL([W7],0) AS [W7],ISNULL([W8],0) AS [W8],ISNULL([W9],0) AS [W9],ISNULL([W10],0) AS [W10]
Then simply plug the two lists into the SQL query. In CF:
<cfscript>
// ...
sqlString = "
SELECT UserName
, #SelectColumns#
FROM (
...
) ST
PIVOT
(
SUM(SalesCount)
FOR XWeek IN ( #PivotColumns# )
) AS StorePivot
";
qPivot = queryExecute( sqlString );
// ...
</cfscript>
Results:
SELECT UserName
, ISNULL([W6],0) AS [W6]
, ISNULL([W7],0) AS [W7]
, ISNULL([W8],0) AS [W8]
, ISNULL([W9],0) AS [W9]
, ISNULL([W10],0) AS [W10]
FROM (
...
) ST
PIVOT (
SUM(SalesCount)
FOR XWeek IN (
[W6],[W7],[W8],[W9],[W10]
)
) AS StorePivot
WHERE oh where are the parentheses?
A few observations about the original query:
The current WHERE clause is incorrect. When mixing AND/OR operators, parentheses must be used to ensure the order of operations. Conceptually, the current query is doing this:
WHERE Condition1 AND Condition2 OR Condition3
It should be using parentheses here:
WHERE Condition1 AND ( Condition2 OR Condition3 )
GETDATE() already returns a datetime value, so there's no need to convert it to a datetime again here:
DATEADD(week, -52, convert(datetime, GETDATE()))
Lastly, there shouldn't be a need for all the concatenation. Strings can usually span multiple lines, and there's always cfsavecontent if needed. Removing all the & will greatly improve readability.
If you're trying to copy the SQL exactly I think you missed the 'W' in the cfset at the top:
<cfset WEEK_2 = 'W' & DATETImeFormat(DateAdd("ww",-2,now()),"w")>
Outputs:
Week: W9 (This is the value of the WEEK_2 variable)
You have this command:
<cfset XX = XX & "ISNULL([#WEEK_2#], 0) AS [#WEEK_2#] ">
Since the week_2 variable has a value of 9, when that command gets executed, it becomes this:
<cfset XX = XX & "ISNULL([9], 0) AS [9] ">
and your query becomes
select username
, 9 as 9
from etc
You are going to have to put some more thought into generating your week numbers.

Trigger to insert new quote number in this format

I am very new at triggers - actually this will be my first one.
What I am trying to achieve is the following:
When I create a new Sales Opportunity, the Quote no field needs to spit out a number starting from this Q1500/09/2017 so Q is the prefix, 1500 is the first quote number, 09 the month and 2017 the year.
Can someone assist me in getting this right - do i need a SP and a table in order for my trigger to work correctly?
Quote_No is a table field so I'm guessing it should look something like this:
CREATE TABLE [dbo].[Quote_Pref_No](
[Yr] [varchar](4) NULL,
[Mth] [varchar](2) NULL,
[Quote_Pref] [varchar](10) NULL,
[Quote_No] [int] NULL
) ON [PRIMARY]
Then the SP:
Create Proc [dbo].[New_Quote_Num] #ClientID varchar(24),#ContactNum int, #Year varchar(4), #mth varchar(2)
As
Begin
Declare #Pref varchar(5),
#Num int,
#QuoteNo varchar(255)
Select #QuoteNo = B.Description
From dbo.AMGR_User_Fields_Tbl A inner join dbo.AMGR_User_Field_Defs_Tbl B
on A.Type_Id = B.Type_Id and A.Code_Id = B.Code_Id and A.Type_Id = 117
Where A.Client_Id = #ClientId and A.Contact_Number = #ContactNum
Select #Pref = Quote_Pref, #Num = Quote_No + 1
From dbo.Quote_Pref_No
Where Yr = #Year and Mth = #Mth
Set #QuoteNum = 'Q/'+Right(#Year,2)+'/'+Right(#mth,2)+'/'+#Pref+case when Len(#Num) <= 3 then Right('000000'+Convert(Varchar(55),#Num),3) else CONVERT(Varchar(55),#Num) end
Insert into dbo.O_QuoteNo(Client_Id,Contact_Number,Type_Id,Code_Id,O_QuoteNo)
Values(#ClientId,#ContactNum,13,0,#QuoteNum)
Update dbo.Quote_Pref_No
Set Quote_No = #Num
Where Yr = #Year and mth = #mth
End
Grant execute on dbo.New_Quote_Num to CRMGroup
GO
I just dont know how to generate the month and year together.
Trigger code:
Create Trigger [dbo].[QuoteNew]
on [dbo].[AMGR_User_Fields_Tbl] after insert
As
Declare #ClientId varchar(24),
#ContactNum int,
#TypeId int,
#Year varchar(4),
#quoteYear varchar(4),
#mth varchar(2)
Select #ClientId = Client_Id,
#ContactNum = Contact_Number,
#TypeId = TYPE_ID,
#Year = CONVERT(varchar(4),Datepart(yyyy,DateCol)) from inserted
#mth = convert(varchar(2), datepart(mm,Datecol)) from inserted
Select #quoteYear = Yr from dbo.quote_Pref_No where Yr = #Year
select #mth = mth from dbo.quote_Pref_No where mth = #mth
If #TypeID = 117 and #QuoteYear is null or #quoteYear = ''
Begin
Execute dbo.New_Year_Certs #Year
Execute dbo.New_quote_Num #ClientId,#ContactNum,#Year
End
If #TypeID = 117 and #quoteYear = #Year
Begin
Execute dbo.New_Cert_Num #ClientId,#ContactNum,#Year
End
GO
Do I need to create a separate SP for month or can I do both month and year in one SP?

How to validate dates in Hash format in MySQL or C++

I need to validate dates in Hash (SHA256) format in MySQL or C++.
For example: date1 < date2 or date1 > date2.
I have this query in MySQL:
SELECT SHA1(CURDATE()) -->'2017-09-06'
and:
SELECT SHA1('2017-09-06') --> '34152f3661d73490ac89b0fe15cb3170aac06bb8'
SELECT SHA1('2017-09-07') --> '0b10f03fb245a6486d6ab5b25a2f050bf87093a5'
But, if I use:
SELECT IF (SHA1('2017-09-06') <= SHA1('2017-09-07') ,'True','False') AS Test;
the result is False, therefore, incorrect!
Don't know why you'd do this, but here's a solution for you.
Here's some assumptions.
You were given two date hashes (two inputs)
You know exactly how the date hashes were created (EG: always in the format of YYYY-MM-DD)
You know the range of your target date (So you can reverse the hash back to the original date)
So in psudocode, you'd do something like this.
date getDateFromHash(string inputHash) {
date startDate = '1911-01-01';
date endDate = '2017-12-31';
for(date checkDate = startDate; checkDate < endDate; checkDate + 1 day) {
if (sha1(checkDate) = inputHash) { return checkDate }
}
return null;
}
date firstDate = getDateFromHash("0b10f03fb245a6486d6ab5b25a2f050bf87093a5"); // 2017-09-07
date secondDate = getDateFromHash("34152f3661d73490ac89b0fe15cb3170aac06bb8"); // 2017-09-06
if (firstDate > secondDate) {
return true;
} else {
return false;
} // compare using default date operators
But honestly speaking, like the comment says, there's no point of hashing date values. Hence why I'm only dropping a quich psudo code for you just to point you in the right direction, if you seriously want to tread down this path.

Checking a date is between two dates

In ColdFusion I can see the code below, however it does not seem to work. I want to make sure discount is only applied if the valid from and to dates are in range, see below.
if (
DATEDIFF("d", discount.ValidFrom(), now()) >= 0
AND
DATEDIFF("d", now(), discount.ValidTo()) <= 0
){
// ALL OK Accept Discount
}
else
{
// Discount is no Longer Valid boo!
}
Try this:
Today = Int(Now());
if ( Today GTE Int(discount.ValidFrom())
AND Today LTE Int(discount.ValidTo())
)
{
// discount is valid
}
else
{
// no longer valid
}
It works because datetimes are basically just numbers - with the integer/whole part being the days and the decimal/fraction part being the time.
So applying the Int function will convert a datetime to a whole day date, and then you can just do a simple numeric comparison to ensure it is within the ranges.
I find this far more readable and understandable than the DateDiff stuff - there's no confusion over the ordering of things, which I think is the problem with your provided code snippet (you've switched both order and lte/gte; you only wanted to change one or the other).
Your logic is a bit off. Right now you're returning
if ({positive_number} and {negative_number})
which returns false. You should be checking if dateDiff("d", today, discount.to()) is also >= 0.
<cfscript>
local = {};
local.start = createDate( 2011, 10, 01 );
local.end = createDate( 2011, 10, 30 );
local.today = now();
local.valid = false;
if ( (dateDiff("d", local.start, local.today) >= 0)
AND (dateDiff("d", local.today, local.end) >= 0) ){
local.valid = true;
}
</cfscript>
<cfoutput>
x < z: #dateDiff("d", local.start, local.today) GTE 0#
<hr />
z < y: #dateDiff("d", local.today, local.end) GTE 0#
<hr />
Valid: #local.valid#
</cfoutput>