I am trying to return the first 'word' in a string by finding the first instance of a space ' ' in the string field Part_Comment. Examples of strings in the field Part_Comment are:
13088V21 () (FAB)
G16707 (FOLD) ()
16636U01.01
I have tried:
substring(Part_Comment from 1 for position(' ' in Part_Comment)-2) as "AssyNo",
which comes up with an error "Incorrect syntax near the keyword 'from'." But it works fine when I just use Part_Comment by itself.
substring(Part_Comment from 1) as "AssyNo",
Same error as above
left(Part_Comment,10) as "AssyNo",
This works, but I need to use the position function or something else to find the ' ' substring. But apparently the position function returns 0 when more than one instance occurs.
I imagine this is a pretty common thing that users want, so there must be an easy solution.
You can do it with LEFT and POSITION like so:
LEFT(Part_Comment, POSITION(' ' in Part_Comment)-1))
EDIT
as #Arioch 'The in comment suggested, safety need to be implemented
CASE POSITION(' ' in Part_Comment)
WHEN 0 THEN 'Part_Comment'
ELSE LEFT(Part_Comment, POSITION(' ' in Part_Comment)-1)
END
Related
For the life of me, it seems I can't filter my TFDQuery using a DateTime field/format. I have this query that needs to "import" filters from a component (cxGrid), among them are:
"Date = " (DateTimeField);
"Value = " (FloatField);
"Supplier = " (StringField);
(And a few others, but those are the more important ones). Date is seconds sensitive, so it has HH:MM:SS, this is necessary for stock/contability purposes.
Now what I mean about "importing" filters is that I'm using the same filters as the ones current marked on a cxGrid. I do so using this simple method:
Filter := cxGridDBTableView.DataController.Filter.FilterText;
Which gives me a string of all the filters currently in use in that cxGrid.
I then toss this string in the filters of my query as in:
MyTFDQuery.Filtered := False;
MyTFDQuery.Filter := Filter;
MyTFDQuery.Filtered := True;
This posed a problem with Value, as we had a display format changing the float to a different format (from, let's say, 2.4 to 2,40) but this has already been fixed. Supplier and the other fields all worked like a charm, mostly because they didn't have a mask/display format.
My problem is when running the DateTime field (Date) filter, I get this error:
[FireDAC][Stan][Eval]-114. Expected []
This field has no display formats or masks of any kind.
I did try searching for this error code online, and couldn't find anything. I did try to change the format of the Date filter, seeing as many people had issues with the format. I have tried all forms of:
MyTFDQuery.Filter := 'Date = ''2021-01-01 10:00:00'''
MyTFDQuery.Filter := 'Date = {dt 2021-01-01 10:00:00}'
MyTFDQuery.Filter := 'Date = ' + Chr(39) + '2021-01-01 10:00:00' + Chr(39)
MyTFDQuery.Filter := 'Date = {CONVERT(''2021-01-01 10:00:00'', DATETIME)}
and many others that I can't recall from the top of my head, right now.
And also tried several different formats for the date... Such as:
YYYY-MM-DD
YYYY-DD-MM
DD-MM-YYYY
MM-DD-YYYY
Or even the separators for that date. I've tried ' - '; ' / '; ' . ' and the such (like 24.02.1982 instead of 24/02/1982). and kept on trying different ways to make this work, with different combinations.
When I searched about this issue online, specially in "how to filter a dataset/tfdquery by datetime", most people were being told to use different formats for the date/datetime to make it work. It seemed everyone had a different solution for this.
I'm not sure what to try anymore. Is this somehow connected to regional settings, as one search result pointed out? Where would those settings be from? The Delphi IDE? FireDAC? The DB I use? Is there something I'm missing?
Basically I want to know what format I should be using to filter my TFDQuery.
Thank you all for reading so far, any help would be highly appreciated. I hope the question is straightforward enough.
PS: I'm sorry for anything wrong I made have done in the making of this question. English is not my native language, and it's been a really long week. Thank you for the patience.
UPDATE: I've identified the error with a lot of guesswork. The milliseconds bit of the datetime is being taken into account when the filter is going to be applied to the dataset, and the cxGrid component would round the seconds (e.g changing '2021-02-01 18:05:03.822' to '2021-02-01 18:05:04').
That way, when the Date = '2021-02-01 18:05:04' would filter something, it wouldn't show up anything. It wasn't an issue with formatting, but rather with equality of datetimes.
To fix this, I followed Brian's advice and made the change:
cxGridDBTableView.DataController.Filter.DateTimeFormat := 'yy-mm-dd hh:mm:ss.zzz'
Now the millisecs are being taken from the filter, and the rounding ignored. Unfortunatelly I'm stuck on the error it gives:
[FireDAC][Stan][Eval]-118. Couldn't convert variant of type (UnicodeString) into type (Date)
Any further help would be highly appreciated.
I've found the "solution" to this problem. I simply assumed the query didn't accept the string filter with milliseconds, maybe some compatibility issues. I'm leaving this here in hopes that someone with a problem like mine can solve it fast, and maybe someone else can improve on this and make it more elegant/efficient.
I broke the string and inserted in a stringlist for easy management:
MyStringListFilters.LineBreak := ' AND ';
MyStringListFilters.Text := Filter;
This would turn a filter's string from:
((Date = ''28/09/2022 18:22:44.789'') OR (DATE = ''11/02/2019 07:18:03.122'')) AND ((Value = 2,4) OR (Value = 7,9)) AND (SUPPLIER = ''My Supplier Name Ltda'')
To:
((Date = ''28/09/2022 18:22:44.789'') OR (DATE = ''11/02/2019 07:18:03.122''))
((Value = 2,4) OR (Value = 7,9))
(SUPPLIER = ''My Supplier Name Inc'')
Now fixing the values is easy by just using a StringReplace:
While i < MyStringListFilters.Count do
if (Copy(MyStringListFilters[i], 2, 5) = 'Value') or (Copy(MyStringListFilters[i], 3, 5) = 'Value') then
StringReplace(MyStringListFilters[i], ',', '.', [rfReplaceAll]);
(When there is two or values, there will be an extra parentheses in front of the string).
Fixing the Date was a bit harder. I had to insert the string inside another string list, and break it up the same way:
//inside of the same while
if (Copy(MyStringListFilters[i], 2, 4) = 'Date') or (Copy(MyStringListFilters[i], 3, 4) = 'Date') then
begin
MyStringListDates.LineBreak := ' OR ';
MyStringListDates.Text := MyStringListFilters[i];
//it keeps on going...
Which further breaks the date string to:
((Date = ''28/09/2022 18:22:44.789'')
(Date = ''11/02/2019 07:18:03.122''))
Be aware: We have to remove the parentheses in the first filter and in the last as well if there is two or more Date filters. We also have to set things up as it was by the end of the loop. Do remember to always increment the index integer of both whiles.
//This happens inside the first while...
while j < MyStringListDates.Count do
begin
TempDate := Copy(MyStringListDates[j], 10, 19);
//This pulls the whole second, ignoring milliseconds from the DB.
MyStringListDates[j] := '((Date >= ' + QuotedStr(TempData) + ') and (Date < ' + QuotedStr(DateTimeToStr(IncSecond(StrToDateTime(TempData)))) + '))';
FixedDate := FixedDate + MyStringListDates[j];
if FixedDate = '' then
begin
// Puts the first parentheses back.
if MyStringListDates.Count > 1 then
FixedDate := '(';
FixedDate := FixedDate + MyStringListDates[j];
end
else
FixedDate := FixedDate + ' OR ' + MyStringListDates[j];
Inc(j);
end
//Remember to add the last parentheses here, if there is more than 1 Date Filter.
I would like to thank #Brian for their help with this solution. I didn't notice the component could be changed so the DateTime would come differently.
I would also like to thank #marc_s for editing the original question. This is my first question on the platform ever, so I didn't know what I was doing (Still don't. Sorry).
Also a special thanks to #Uwe Raabe, I've also used their answer on how to split strings using a multiple character delimiter on this problem. Here's the link to that question they answered:
How to split string by a multi-character delimiter?
I've been tasked with fixing some SQL code that doesn't work. The query reads from a view against a predicate. The query right now looks like so.
SELECT TOP (100) Beginn
FROM V_LLAMA_Seminare
//Removal of the following line makes the query successful, keeping it breaks it
where Beginn > (select cast (getdate() as smalldatetime))
order by Beginn desc
When I run the above query, I am greeted with the following error.
Msg 295, Level 16, State 3, Line 1
Conversion failed when converting character string to smalldatetime data type.
I decided to remove the WHERE clause, and now it runs returning 100 rows.
At first, I thought that behind the scenes, SQL Server was somehow including my predicate when bringing back the View . But then I investigated how the View was being created, especially the Beginn field, and at no point does it return a String.
Long story short, the column that becomes the Beginn field is a BIGINT timestamp like 201604201369.... The original user transforms this BIGINT to a smalldatetime using the following magic.
....
CASE WHEN ma.datum_dt = 0
THEN null
ELSE CONVERT(smalldatetime, SUBSTRING(CAST(ma.datum_dt AS varchar(max)),0,5) + '-' +
SUBSTRING(CAST(ma.datum_dt AS varchar(max)),5,2) + '-' +
SUBSTRING(CAST(ma.datum_dt AS varchar(max)),7,2) + ' ' +
SUBSTRING(CAST(ma.datum_dt AS varchar(max)),9,2) +':'+
SUBSTRING(CAST(ma.datum_dt AS varchar(max)),11,2) +':' +
RIGHT(CAST(ma.datum_dt AS varchar(max)),2)) END AS Beginn
...
My last attempt at finding the problem was to query the view and run the function ISDATE over the Beginn column and see if it returned a 0 which it never did.
So my question is two fold, "Why does a predicate break something" and two "Where on earth is this string error coming from when the Beginn value is being formed from a BIGINT".
Any help is greatly appreciated.
This problem is culture related...
Try this and then change the first SET LANGUAGE to GERMAN
SET LANGUAGE ENGLISH;
DECLARE #bi BIGINT=20160428001600;
SELECT CASE WHEN #bi = 0
THEN null
ELSE CONVERT(datetime, SUBSTRING(CAST(#bi AS varchar(max)),0,5) + '-' +
SUBSTRING(CAST(#bi AS varchar(max)),5,2) + '-' +
SUBSTRING(CAST(#bi AS varchar(max)),7,2) + ' ' +
SUBSTRING(CAST(#bi AS varchar(max)),9,2) +':'+
SUBSTRING(CAST(#bi AS varchar(max)),11,2) +':' +
RIGHT(CAST(#bi AS varchar(max)),2)) END AS Beginn
It is a very bad habit to think, that date values look the same everywhere (Oh no, my small application will never go international ...)
Try to stick to culture independent formats like ODBC or ISO
EDIT
A very easy solution for you actually was to replace the blank with a "T"
SUBSTRING(CAST(ma.datum_dt AS varchar(max)),7,2) + 'T' +
Then it's ISO 8601 and will convert...
The solution was found after looking through #Shnugo's comment. When I took my query which contained the Bigint->Datetime conversion logic, and put it into a CTE with "TOP 100000000" to avoid any implicit conversion actions, my query worked. Here is what my view looks like now with some unimportant parts omitted.
---Important part---
CREATE VIEW [dbo].[V_SomeView] AS
WITH CTE AS (
SELECT TOP 1000000000 ma.id AS MA_ID,
---Important part---
vko.extkey AS ID_VKO,
vko.text AS Verkaufsorganisation,
fi.f7000 AS MDM_Nr,
vf.f7105 AS SAPKdnr,
CASE WHEN ma.datum_dt = 0 --Conversion logic
CASE WHEN ma.endedatum_dt = 0 --Conversion logic
CONVERT(NVARCHAR(MAX),art.text) AS Art,
.....
FROM [ucrm].[dbo].[CRM_MA] ma,
[ucrm].[dbo].[CRM_fi] fi,
[ucrm].[dbo].[CRM_vf] vf,
[ucrm].[dbo].[CRM_ka] vko,
[ucrm].[dbo].[CRM_ka] art,
[ucrm].[dbo].[CRM_ka] kat
where ma.loskz = 0
and fi.loskz = 0
and vf.loskz = 0
and fi.F7029 = 0
and vf.F7023 = 0
...
GROUP BY ma.id,
vko.extkey,
vko.text,
fi.f7000 ,
vf.f7105,
ma.datum_dt,
ma.endedatum_dt,
....
)
select * FROM CTE;
I am using a concatenation statement to return Last Name, First Name Middle initial with a period (.). Ex: “Brown, John R.”. The statement is as follows:
IF([Middle Name] IS NULL )
THEN (trim([Last Name])+', '+trim([First Name]))
ELSE (trim([Last Name])+', '+trim([First Name])+' '+substring(nullif([Middle Name],' '),1,1)+'.'))
However, the statement is randomly omitting several of the names in the returned result. If I do not use the "nullif" option, it still returns periods where there is no middle initial.
Any help would be appreciated.
Thanks
How about replace the whole thing with:
SELECT trim([Last Name])+', '+trim([First Name]) + Isnull(' ' + LEFT([Middle NAME],1) + '.','') AS FullName
Are all the first and last names filled in (NOT Null)?
What am I missing in this code below that will cause the error:
Msg 170, level 15, line 113 line 113:
Incorrect syntax near
'actual_completion_date'.
update #Loss_mit_step
set
[STEP924_COMPL_DATE] = Case when step_code ='924' then ls_actual_completion_date else ' ' end,
[STEP926_COMPL_DATE] = Case when step_code ='926' then ls_actual_completion_date else ' ' end,
[STEP927_COMPL_DATE] = Case when step_code ='927' then ls_actual_completion_date else ' ' end,
[STEP928_COMPL_DATE] = Case when step_code ='928' then ls_actual_completion_date else ' ' end,
[APPROVAL_DATE] = Case when step_code ='Q28' then ls_actual_completion_date else ' ' end
What you posted is syntactically correct, so you cannot get a syntax error. It actually parses fine. Your error message mentions actual_completion_date but you have no such token in your post. So obviously you posted an error from a different T-SQL.
You appear to have an extra comma in the statement, at the very end.
I suggest you comment out each of the "case" lines, one by one, until you find out what the problem is, or until you only have one line left.
I found the cause of the error: a space in front of actual_completion_date on the first line.
We have a web application that uses SQL Server 2008 as the database. Our users are able to do full-text searches on particular columns in the database. SQL Server's full-text functionality does not seem to provide support for hit highlighting. Do we need to build this ourselves or is there perhaps some library or knowledge around on how to do this?
BTW the application is written in C# so a .Net solution would be ideal but not necessary as we could translate.
Expanding on Ishmael's idea, it's not the final solution, but I think it's a good way to start.
Firstly we need to get the list of words that have been retrieved with the full-text engine:
declare #SearchPattern nvarchar(1000) = 'FORMSOF (INFLECTIONAL, " ' + #SearchString + ' ")'
declare #SearchWords table (Word varchar(100), Expansion_type int)
insert into #SearchWords
select distinct display_term, expansion_type
from sys.dm_fts_parser(#SearchPattern, 1033, 0, 0)
where special_term = 'Exact Match'
There is already quite a lot one can expand on, for example the search pattern is quite basic; also there are probably better ways to filter out the words you don't need, but it least it gives you a list of stem words etc. that would be matched by full-text search.
After you get the results you need, you can use RegEx to parse through the result set (or preferably only a subset to speed it up, although I haven't yet figured out a good way to do so). For this I simply use two while loops and a bunch of temporary table and variables:
declare #FinalResults table
while (select COUNT(*) from #PrelimResults) > 0
begin
select top 1 #CurrID = [UID], #Text = Text from #PrelimResults
declare #TextLength int = LEN(#Text )
declare #IndexOfDot int = CHARINDEX('.', REVERSE(#Text ), #TextLength - dbo.RegExIndexOf(#Text, '\b' + #FirstSearchWord + '\b') + 1)
set #Text = SUBSTRING(#Text, case #IndexOfDot when 0 then 0 else #TextLength - #IndexOfDot + 3 end, 300)
while (select COUNT(*) from #TempSearchWords) > 0
begin
select top 1 #CurrWord = Word from #TempSearchWords
set #Text = dbo.RegExReplace(#Text, '\b' + #CurrWord + '\b', '<b>' + SUBSTRING(#Text, dbo.RegExIndexOf(#Text, '\b' + #CurrWord + '\b'), LEN(#CurrWord) + 1) + '</b>')
delete from #TempSearchWords where Word = #CurrWord
end
insert into #FinalResults
select * from #PrelimResults where [UID] = #CurrID
delete from #PrelimResults where [UID] = #CurrID
end
Several notes:
1. Nested while loops probably aren't the most efficient way of doing it, however nothing else comes to mind. If I were to use cursors, it would essentially be the same thing?
2. #FirstSearchWord here to refers to the first instance in the text of one of the original search words, so essentially the text you are replacing is only going to be in the summary. Again, it's quite a basic method, some sort of text cluster finding algorithm would probably be handy.
3. To get RegEx in the first place, you need CLR user-defined functions.
It looks like you could parse the output of the new SQL Server 2008 stored procedure sys.dm_fts_parser and use regex, but I haven't looked at it too closely.
You might be missing the point of the database in this instance. Its job is to return the data to you that satisfies the conditions you gave it. I think you will want to implement the highlighting probably using regex in your web control.
Here is something a quick search would reveal.
http://www.dotnetjunkies.com/PrintContent.aspx?type=article&id=195E323C-78F3-4884-A5AA-3A1081AC3B35
Some details:
search_kiemeles=replace(lcase(search),"""","")
do while not rs.eof 'The search result loop
hirdetes=rs("hirdetes")
data=RegExpValueA("([A-Za-zöüóőúéáűíÖÜÓŐÚÉÁŰÍ0-9]+)",search_kiemeles) 'Give back all the search words in an array, I need non-english characters also
For i=0 to Ubound(data,1)
hirdetes = RegExpReplace(hirdetes,"("&NoAccentRE(data(i))&")","<em>$1</em>")
Next
response.write hirdetes
rs.movenext
Loop
...
Functions
'All Match to Array
Function RegExpValueA(patrn, strng)
Dim regEx
Set regEx = New RegExp ' Create a regular expression.
regEx.IgnoreCase = True ' Set case insensitivity.
regEx.Global = True
Dim Match, Matches, RetStr
Dim data()
Dim count
count = 0
Redim data(-1) 'VBSCript Ubound array bug workaround
if isnull(strng) or strng="" then
RegExpValueA = data
exit function
end if
regEx.Pattern = patrn ' Set pattern.
Set Matches = regEx.Execute(strng) ' Execute search.
For Each Match in Matches ' Iterate Matches collection.
count = count + 1
Redim Preserve data(count-1)
data(count-1) = Match.Value
Next
set regEx = nothing
RegExpValueA = data
End Function
'Replace non-english chars
Function NoAccentRE(accent_string)
NoAccentRE=accent_string
NoAccentRE=Replace(NoAccentRE,"a","§")
NoAccentRE=Replace(NoAccentRE,"á","§")
NoAccentRE=Replace(NoAccentRE,"§","[aá]")
NoAccentRE=Replace(NoAccentRE,"e","§")
NoAccentRE=Replace(NoAccentRE,"é","§")
NoAccentRE=Replace(NoAccentRE,"§","[eé]")
NoAccentRE=Replace(NoAccentRE,"i","§")
NoAccentRE=Replace(NoAccentRE,"í","§")
NoAccentRE=Replace(NoAccentRE,"§","[ií]")
NoAccentRE=Replace(NoAccentRE,"o","§")
NoAccentRE=Replace(NoAccentRE,"ó","§")
NoAccentRE=Replace(NoAccentRE,"ö","§")
NoAccentRE=Replace(NoAccentRE,"ő","§")
NoAccentRE=Replace(NoAccentRE,"§","[oóöő]")
NoAccentRE=Replace(NoAccentRE,"u","§")
NoAccentRE=Replace(NoAccentRE,"ú","§")
NoAccentRE=Replace(NoAccentRE,"ü","§")
NoAccentRE=Replace(NoAccentRE,"ű","§")
NoAccentRE=Replace(NoAccentRE,"§","[uúüű]")
end function