I have an SQL query :
SELECT DATEDIFF(deadline,CURDATE()) FROM tasks WHERE 1
The Result is : 3
How can I return the result as : 3 Days instead of 3
I know that I can manually append the string from my C# code something like :
string result = getSqlresult();
string result += " Days";
But I want to get the result directly as 3 Days from MySQL database.
The reason :
I'm binding information directly to datagridview and therefore, In order to modify the result i need to iterate through all rows and update them. So to increase performance, I need to get the result directly from database as 3 Days instead of 3
Anyhelp would be highly appreciated
you can concatenate the string Days into the result of DATEDIFF using CONCAT.
SELECT CONCAT(DATEDIFF(deadline,CURDATE()), ' Days')
FROM tasks
WHERE 1
if you are using old versions of MySQL, convert it to string so you will not get bolb result.
SELECT CONCAT(CAST(DATEDIFF(deadline,CURDATE()) AS CHAR(5)), ' Days')
FROM tasks
WHERE 1
UPDATE 1
SELECT CASE
WHEN DATEDIFF(deadline,CURDATE()) >= 0
THEN CONCAT(DATEDIFF(deadline,CURDATE()), ' Days')
ELSE CONCAT('Expired since ', DATEDIFF(deadline,CURDATE()) * -1, ' Days')
END
FROM tasks
SQLFiddle Demo
Related
I'm currently working on a search method in C# for a SQL Server database.
The regex:
/(a)|(b)|(c)|(d)/g
a, b, c & d are the search keywords.
The string that I apply the regex to:
a fdh eidb
Consists of random words(represented as letters) and some of the keywords from above.
Expected output:
3 keywords matches.
But how does a SQL query for SQL Server look like that returns a table with a Matches column with the keyword match count for each row?
I know how to do this in C# but I want to do it in the search query itself so I can sort the output.
Thanks for any help towards the right direction :)
I don't think there is a way to do regular expressions in SQL Server queries - other than adding some managed code which adds that functionality.
Here is an example of how to do that - SQL Server Regular expressions in T-SQL
It seems that REGEX wasn't really the solution.
Instead I wrote multiple SQL functions that do the job:
CREATE FUNCTION [dbo].[KeywordMatches]
(
#String nvarchar(1000),
#Keywords nvarchar(1000),
#Seperator text
)
RETURNS INT
AS
BEGIN
DECLARE #Count int = 0;
DECLARE #Keyword varchar(1000);
DECLARE KeywordsCursor CURSOR FOR
SELECT *
FROM [dbo].StringSplit(#Keywords, #Seperator)
OPEN KeywordsCursor
FETCH NEXT FROM KeywordsCursor INTO #Keyword
WHILE ##FETCH_STATUS = 0
BEGIN
IF #String LIKE '%' + #Keyword + '%'
SET #Count += 1
FETCH NEXT FROM KeywordsCursor INTO #Keyword
END
CLOSE KeywordsCursor
DEALLOCATE KeywordsCursor
RETURN #Count
END
And (fallback for server 2016 split_string):
CREATE FUNCTION [dbo].[StringSplit]
(
#SeperatedWords nvarchar(1000),
#Seperator char
)
RETURNS #Words TABLE
(
Word nvarchar(1000)
)
AS
BEGIN
DECLARE #Position int = -1
SET #SeperatedWords += #Seperator
WHILE (#Position > 0 OR #Position = -1)
BEGIN
SET #SeperatedWords = SUBSTRING(#SeperatedWords, #Position + 1, LEN(#SeperatedWords) - #Position + 1)
SET #Position = CHARINDEX(#Seperator, #SeperatedWords)
/* Only add words that have a length bigger then 0 */
IF #Position > 1
/* Add the word to the table */
INSERT INTO #Words(Word) VALUES(LEFT(#SeperatedWords, #Position - 1))
END
RETURN
END
Usage:
SELECT Id, Title, [dbo].KeywordMatches(Title, 'blue red green', ' ') AS Matches
FROM Questions
ORDER BY Matches DESC, Date DESC
Above query orders by the amount of keywords found in the title and date.
I also read about full text search which is probably faster then this solution.
Suppose I have a MySQL table of one column: "Message". It is of type TEXT.
I now want to query all rows, but the text can be large (not extremely large but large) and I only want to get a summary of them. For example the result can be populated into a list.
Is there a way to trim the text to a specific length (say, 10 characters), and add ellipsis if the text is trimmed?
For example:
Message
-----------
12345678901234
1234567890
12345
12345678901
Query result:
1234567...
1234567890
12345
1234567...
Thanks!
select case when length(message) > 7
then concat(substring(message, 1, 7), '...')
else message end as adapted_message
from ...
to test/confirm:
SELECT CASE WHEN LENGTH('1234567890') > 7
THEN CONCAT(SUBSTRING('1234567890', 1, 7), '...')
ELSE '1234567890' END AS adapted_message
UNION
SELECT CASE WHEN LENGTH('12345') > 7
THEN CONCAT(SUBSTRING('12345', 1, 7), '...')
ELSE '12345' END AS adapted_message
Here's a simple one line solution:
IF(CHAR_LENGTH(message) > 10, CONCAT(LEFT(message, 7),"..."), message)
or...
SELECT CONCAT(LEFT(message, 7), IF(LENGTH(message)>7, "…", ""))
FROM table
You can declare a new ELLIPSIS function in order to make your query readable:
DELIMITER //
CREATE FUNCTION ELLIPSIS ( str TEXT, max_length INT )
RETURNS TEXT
BEGIN
DECLARE str_out TEXT;
IF LENGTH(str) <= max_length THEN
SET str_out = str;
ELSE
SET str_out = CONCAT(SUBSTR(str, 1, max_length-3), '...');
END IF;
RETURN str_out;
END; //
DELIMITER ;
Then you simply do:
SELECT ELLIPSIS(Message, 10);
Have a look at the MySQL string functions, documented here. You should be able to use some combination of substring and concat to achieve your desired behaviour.
My approach:
Let x be the maximum number of characters to display (therefore x + 3 dots will be the longest string displayed)
You always want LEFT(field,x)
If LENGTH(field) > x + 3, append 3 dots
Otherwise if LENGTH(field) > x, append the remainder of field
SELECT CONCAT(
LEFT(field,x),
IF(LENGTH(field) > x+3,
'...',
IF(LENGTH(field) > x,
MID(field,x+1,LENGTH(field)),
''
)
)
) FROM table
I have tried several methods (by position, by white space, regex) but cannot figure how to best parse the following lines as a table. For e.g. let's say the two lines I want to parse are:
Bonds Bid Offer (mm) (mm) Chng
STACR 2015-HQA1 M1 125 120 5 x 1.5 0
STACR 2015-HQA12 2M2 265 5 x -2
I want that it should parse as follows for [BondName] [Bid] [Offer]:
[STACR 2015-HQA1 M1] [125] [120]
[STACR 2015-HQA12 2M2] [265] [null]
Notice the null which is an actual value and also the spaces should be retained in the bond name. FYI, the number of spaces in the Bond Name will be 2 as in the above examples.
Edit: Since many of you have asked for code here it is. The spaces between the points can range from 1-5 so I cannot reply on spaces (it was straightforward then).
string bondName = quoteLine.Substring(0, 19);
string bid = quoteLine.Substring(19, 5).Trim();
string offer = quoteLine.Substring(24, 6).Trim();
The only way I can see this working is that:
1st data point is STACR (Type)
2nd data point is the year and Series
(e.g. 2015-HQA1)
3rd data point is Tranche (M1)
4th data point is bid
(e.g. 125 ** bid is always available **)
5th data point is offer (e.g. 120 but can be blank
or whitespace which introduces complexity)
With the current set of requirements, I'm assuming the following
1. String starts with 3 part bond name
2. Followed by bid
3. Followed by offer (optional)
4. After that, we'll have something like ... x ... ... (we'll use x as reference)
Given they are valid, you can use the following code
var str = "STACR 2015-HQA1 M1 125 120 5 x 1.5 0"; //your data
var parts = str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
//we'll use this pattern : <3 part bond name> <bid> <offer/null> <something x ....>
var xIsAt = parts.IndexOf("x"); //we'll use x as reference
if (xIsAt > 2) //first three are BondName
parts.RemoveRange(xIsAt - 1, parts.Count - xIsAt + 1); //remove "5 x 1.5 ..."
var bond = string.Join(" ", parts.Take(3)); //first 3 parts are bond
var bid = parts.Count > 3 ? parts.ElementAt(3) : null; //4th is bid
var offer = parts.Count > 4 ? parts.ElementAt(4) : null; //5th is offer
[EDIT]
I did not account for the blank 'Offer' so this method will fail on a blank 'Offer'. Looks like someone already has a working answer, but i'll leave the linq example for anyone that finds it useful.
[END EDIT]
Linq based option.
Split the string by spaces, and remove empty spaces. Then reverse the order so you can start from the back and work your way forward. The data appears more normalized at the end of the string.
For each successive part of the line, you skip the previous options and only take what you need. For the last part which is the long string, you skip what you don't need, then reverse the order back to normal, and join the segments together with spaces.
string test = "STACR 2015-HQA1 M1 125 120 5 x 1.5 0";
var split_string_remove_empty = test.Split(new char[]{ ' ' }, StringSplitOptions.RemoveEmptyEntries).Reverse();
var change = split_string_remove_empty.Take(1)
.SingleOrDefault();
var mm2 = split_string_remove_empty.Skip(1)
.Take(1)
.SingleOrDefault();
var mm3 = split_string_remove_empty.Skip(3)
.Take(1)
.SingleOrDefault();
var offer = split_string_remove_empty.Skip(4)
.Take(1)
.SingleOrDefault();
var bid = split_string_remove_empty.Skip(5)
.Take(1)
.SingleOrDefault();
var bonds = string.Join(" ", split_string_remove_empty.Skip(6)
.Reverse());
Output:
I have a comma separated string stored in database.
E.g.: record1 = "1,3,5,7,9,10" and record2 = "4,5,10"
And I have a given information, E.g.: 1.
I have to select the record using LINQ that contains the given info of 1.
The result returned should be record1.
If I were to use .contains() solely, it's not accurate as record2 will be returned as well.
How can I achieve that? Is it possible to achieve that in a single LINQ query?
Thanks for advise !
With a single LINQ-to-objects query:
string[] records = new[] { record1, record2 };
string record = records.FirstOrDefault(r => r.Split(',').Any(s => s == "1"));
Demo
First of all I would like to mention what #Tim Schmelter said -
Have you noticed already that the real problem is your creepy
datamodel? Use a table with real records instead of a column with a
comma separated string.
It is not a good practice to use a datamodel where you need string split match. Because it leads to inefficient systems and not to mention slow queries. But yet, if you really need a solution why not try this -.
There are four occasions where you will get a match,
A prefix match - starting with
Inner Match - contains with
Suffix Match - ends with
The only match - only one item and this is it
considering the scenario I am suggesting the solution below -
s is the value looking for say "1"
string prefixMatch = s + ",";
string suffixMatch = "," + s;
string innerMatch = "," + s + ",";
string record = <dbRecords>.FirstOrDefault(r=> r.StartsWith(prefixMatch) ||
r.Contains(innerMatch) || r.EndsWith(suffixMatch) ||
(!r.Contains(",") && r == s));
The reason for such a detailed query is to keep your memory utilisation less and letting the SQL query do the hard work of finding the results because this query will support LINQ-to-SQL conversion.
If i understand you correctly, you need as result record that contains "1". So you can use:
private bool GerRecord(string record)
{
string[] arr=record.Split(',');
return arr.Contains("1");
}
Instead of searching 1 you can try 1,(1 and comma combined) for searching in Contains in linQ
I have a scheduled job which runs at 12:45:00 AM. Now through SP I want to get this time. I am running this query in my SP:
EXEC msdb.dbo.sp_help_job
#job_name = N'Daily Trends',
#job_aspect = N'SCHEDULES' ;
This query shows result with a column
active_start_time
4500
Expected Output: 12:45:00 AM.
Can you please suggest how to show the time with Am/PM.
Edit: I am calling this SP from c# code. If anybody can suggest how i can convert the time in proper format in c# code will also be helpful.
As the time value seems to be stored as HHMMSS with the hour (HH) optional I think you need to check if the length of the string is four chars (or maybe if the value exceeds 115959, whichever is faster). A query like this should work:
SELECT CASE
WHEN Len(active_start_time) = 4 THEN Cast(
Dateadd(minute, active_start_time /
100, '00:00') AS TIME)
ELSE LEFT(RIGHT('0' + Cast(active_start_time AS VARCHAR), 6), 2)
+ ':'
+ Substring(RIGHT('0' + Cast(active_start_time AS VARCHAR), 6), 3,
2)
+ ':'
+ RIGHT(Cast(active_start_time AS VARCHAR), 2)
END AS [Start time]
FROM msdb..sysschedules
INNER JOIN msdb.dbo.sysjobschedules
ON msdb.dbo.sysjobschedules.schedule_id =
msdb..sysschedules.schedule_id
INNER JOIN msdb.dbo.sysjobs
ON msdb.dbo.sysjobs.job_id = msdb.dbo.sysjobschedules.job_id
WHERE msdb.dbo.sysjobs.name = 'Daily Trends'
I didn't test it with that many values but I believe it should work, or at least give you a hint on how to proceed. Accessing the msdb tables directly might be a bad idea and if I recall right, there are some views that give access to similar information and it could be better to use them.
You can use the sysjobschedules table however the date will be the same.
This blog should help parse the date/time:
http://blog.sqlauthority.com/2008/12/22/sql-server-find-next-running-time-of-scheduled-job-using-t-sql/
so, to get the data to look like a HH:MM:SS format, the following SQL would work:
SELECT LEFT(RIGHT('0' + Cast(active_start_time AS VARCHAR), 6), 2)
+ ':'
+ Substring(RIGHT('0' + Cast(active_start_time AS VARCHAR), 6), 3, 2)
+ ':'
+ RIGHT(Cast(active_start_time AS VARCHAR), 2)
FROM msdb..sysschedules