How to pull part of a NVARCHAR field based on certain text? - sql-server-2008

Im sorry for the terrible title, I can't think of a better way to state it...
Essentially, i have a NVARCHAR field that is filled with various production comments that look like this:
(1/22/2015 (blujo) - WO113315 In Process)
I want to pull just the 'WO113315' part out of that field. These are work order numbers, and will obviously be different in each row of the table. So for any field that contains WO% somewhere in it, i want to pull that WO% plus the next 6 characters after it. I don't think trim will work b/c the WO% number could be anywhere in the field. But it will always start with WO%.

You can use a combination of SUBSTRING and CHARINDEX.
DECLARE #VAL AS NVARCHAR(100) = '1/22/2015 (blujo) - WO113315 In Process'
SELECT SUBSTRING(#VAL, CHARINDEX('WO', #VAL), 8)
If you know that the work order number will always show up after the dash, you can also use the following to ensure you are starting the search at this point.
DECLARE #VAL AS NVARCHAR(100) = '1/22/2015 (WOblujo) - WWO113315 In Process'
SELECT SUBSTRING(#VAL, CHARINDEX('WO', #VAL, CHARINDEX('-',#VAL)), 8)
EDIT: If you're not guaranteed of a WO code, then the following case statement can pick it up. At this point, I would suggest saving these results onto a new field on the table (or maybe a persisted computed column) so that your server doesn't need to go through this each time.
DECLARE #VAL AS NVARCHAR(100) = '1/22/2015 (blujo) - RW13315 In Process'
SELECT CASE WHEN CHARINDEX('WO', #VAL, CHARINDEX('-',#VAL)) > 0 THEN
SUBSTRING(#VAL, CHARINDEX('WO', #VAL, CHARINDEX('-',#VAL)), 8)
WHEN CHARINDEX('RW', #VAL, CHARINDEX('-',#VAL)) > 0 THEN
SUBSTRING(#VAL, CHARINDEX('RW', #VAL, CHARINDEX('-',#VAL)), 8)
ELSE NULL END

Related

DBGrid / DataSet fails to sort as per sql statement set in CommandText

I'm using the following in my CommandText property of the DataSet I'm using:
SELECT *
FROM table_name
ORDER BY FIELD(priority, 'urgent', 'normal'),
FIELD(state, 'wait', 'executed', 'done')
It should sort the data I'm displaying in the DBGrid connected to this DataSet, like this:
Rows containing urgent in the priority column should start the DBGrid list.
Then the list should continue with the ones marked as normal in the priority column,
followed by the ones marked as wait in the state column,
followed by the ones marked as executed in the state column,
and finally the list ends with the ones marked as done in the state column.
But It doesn't, well actually it kind of does, but it's actually backwards.
Here is a quick video I've made to show you whats happening, maybe you can get a clearer view this way:
Video of what's happening
I'm guessing it's because of either the ID column I'm using or the Date column but if so, I have no idea how and why.
This is how those 2 columns look like/are set up:
ID column is set as Primary and Unique and Auto_Increment - that's it, no Index or any of the other options
If it's not those 2 columns the problem, then maybe the DBGrid?
I'm using RAD Studio 10 Seattle, dbExpress components (TSimpleDataSet, etc) and MySQL db
Any thoughts on how to fix this? thanks!
You are making life unnecessarily difficult for yourself going about it the way you are.
It's not necessary to get the server to do the sorting (by using an ORDER BY clause and it's arguably better to do the sorting in the client rather than on the server, because the client typically has computing power to spare whereas the server may not.
So, this is my suggested way of going about it:
Drop the ORDER BY from your SQL and just do a a SELECT * [...].
Replace your SimpleDataSet by a ClientDataSet and define persistent TFields on it. The reason for making this change is so as to be able to create two persistent fields of type fkInternalCalc.
In the TFields editor in the Object Inspector, define two fkInternalCalc fields called something like PriorityCode and StateCode.
Set the IndexFieldNames property of your dataset to 'PriorityCode;StateCode'.
In the OnCalcFields event of your dataset, calculate values for the PriorityCode and StateCode that will give the sort order you wish the data rows to have.
Something like:
procedure TForm1.ClientDataSet1CalcFields(DataSet: TDataSet);
var
S : String;
PriorityCodeField,
StateCodeField : TField;
iValue : Integer;
begin
PriorityCodeField := ClientDataset1.FieldByName('PriorityCode');
StateCodeField := ClientDataset1.FieldByName('StateCode');
S := ClientDataset1.FieldByName('Priority').AsString;
if S = 'urgent' then
iValue := 1
else
if S = 'normal' then
iValue := 2
else
iValue := 999;
PriorityCodeField.AsInteger := iValue;
S := ClientDataset1.FieldByName('State').AsString;
if S = 'wait' then
iValue := 1
else
if S = 'executed' then
iValue := 2
else
if S = 'done' then
iValue := 3
else
iValue := 999;
StateCodeField.AsInteger := iValue;
end;
Actually, it would be better (faster, less overhead) if you avoid using FieldByName and just use the fields that the Fields that the OI's Tfields editor creates, since these will be automatically bound to the ClientDataSet's data fields when it is opened.
Btw, it's useful to bear in mind that although a TClientDataSet cannot be sorted on a field defined in the TFields editor as Calculated, it can be sorted on an InternalCalc field.

I need to concat two numbers in mysql

set n=901234567;
set p=0;
insert into try values (
concat(fname,i),
concat(sname,i),
concat(age,i),
concat(email,i,id),
concat(n,p)
);
set n=n+1;
set i=i+1;
concat is working for first four columns.but its not working for concating n and p.here am incrementing the value of n .And for every incrementation the value in p i.e 0 sholud be added at the end of the value of n.
What are n and p? System variables? Most probably not. There is no need to search them into the list of MySQL server system variables, their names are too short, there is no chance to find them there.
Oh, wait! They are user-defined variables. Or, at least, this is what you want them to be. Except that the user-defined MySQL variables are always prefixed with #.
Back to the code, n and p are not user-defined variables and the user is not allowed to create system variables. MySQL returns the error Unknown system variable 'n' on the first SET query. Case closed.
Let's try to make it work:
set #n=901234567;
set #p=0;
insert into try values (
concat(fname,#i),
concat(sname,#i),
concat(age,#i),
concat(email,#i,id),
concat(#n,#p)
);
set #n=#n+1;
set #i=#i+1;
If the other names present in the queries (fname, sname, age, email, id) are also variables then put # in front of them.

How to find out the changes happened for all objects

How I can find out the changes happened in database like modifying functions, table indexes, procedures and adding or removing columns.
Here in this query
select * from sys.objects
where type IS NOT NULL
and modify_date between '2013-07-21' and '2013-07-29'
but here I am getting created objects list and modifying list, but if I deleted any object it is not showing anything.
How can I get the all the changes happened in database between specific dates?
Try a source control solution for SQL. I've used RedGate's SQL Source Control before, and it records a history of changes like this, including who made the change, and what was changed.
http://www.red-gate.com/products/sql-development/sql-source-control/
It's a bit expensive, but it's good. I don't know if there's a way to do it (especially deletions) just with SQL itself.
Many of these incidents are recorded in the default trace.
DECLARE #path NVARCHAR(260);
SELECT
#path = REVERSE(SUBSTRING(REVERSE([path]),
CHARINDEX(CHAR(92), REVERSE([path])), 260)) + N'log.trc'
FROM sys.traces
WHERE is_default = 1;
SELECT
LoginName,
HostName,
StartTime,
ObjectName,
TextData -- may or may not be populated
FROM sys.fn_trace_gettable(#path, DEFAULT)
WHERE EventClass IN
(
164, -- object:altered
46, -- object:created
47 -- object:deleted
)
AND StartTime >= '20130721' AND StartTime < '20130730';
Why you should never use BETWEEN for date range queries.

Gettiing Year from another table

I have a field named 'SALARY ON' in which data(year-month) entered is in format '2012-01'(datatype varchar) in table named Table1.For creating a sp i need to take only 2012 from above mentioned table field. How can I do this.
Please help me to solve this.
In the simplest case, a 'SUBSTRING' and 'CAST' will do it for you:
SELECT CAST(SUBSTRING([SALARY ON], 1, 4) AS INT) FROM SALARY
This depends in the fact that the date has been entered in the format YYYY-MM. If you're checking this in a constraint, then the above sample will be fine. Otherwise, you'll need to do some pattern checking before you try to convert it:
SELECT CASE WHEN [SALARY ON] LIKE '[0-9][0-9][0-9][0-9]-[0-9][0-9]' THEN SUBSTRING([SALARY ON], 1, 4) AS INT) ELSE -1 END
You can then take all of the years returned as -1 and raise an error to the user, filter them out, write them to a log file, etc, depending on the environment in which the sp is being called.

SQL Server 2008 SELECT * FROM #variable?

It is possible?
DECLARE #vTableName varchar(50)
SET #vTableName = (SELECT TableName FROM qms_Types WHERE Id = 1)
SELECT * FROM #vTableName
I have this error:
Msg 1087, Level 16, State 1, Line 3 Must declare the table variable
"#vTableName".
Short answer: No.
Long answer: Noooooooooooooooooooooooooooooooooooooo. Use dynamic SQL if you have to, but if you're structuring your tables in a way where you don't know the table name ahead of time, it might benefit you to rethink your schema.
Here is a great resource for learning how to use dynamic SQL: The Curse and Blessings of Dynamic SQL
if you're trying to select from a table of that name, then you can do something like this:
DECLARE #vTableName varchar(50)
SET #vTableName = (SELECT TableName FROM qms_Types WHERE Id = 1)
EXECUTE('SELECT * FROM [' + #vTableName + ']')
my solution for this:
EXECUTE('SELECT * FROM ' + TableName + '')
It seems as though different folks are interpreting the OP differently.
I'm pretty sure the OP is asking for this type of concept / ability / maneuver...
"Put a table name into a variable and then use that variable as though it were a table name."
DECLARE #TableIWantRecordsFrom varchar(50)
-- ^^^^^^^^^^^^^^^^^^^^^^
SET #TableIWantRecordsFrom = (SELECT TableName FROM qms_Types WHERE Id = 1) -- (L1)
-- ^^^^^^^^^^^^^^^^^^^^^^
-- Let's say, at this point, #TableIWantRecordsFrom ... contains the text 'Person'
-- ^^^^^^^^^^^^^^^^^^^^^^
-- assuming that is the case then...
-- these two queries are supposed to return the same results:
SELECT top 3 fname,lname,mi,department,floor FROM Person
-- ^^^^^^
SELECT top 3 fname,lname,mi,department,floor FROM #TableIWantRecordsFrom -- (L2)
-- ^^^^^^^^^^^^^^^^^^^^^^
From reading all the responses and answers, it appears that this kind of maneuver can't be done - unless - you use dynamic SQL which...
can be a bit of a pain to create and maintain and
can be more work to create than the time it "saves" you in the future.
================================================================
There are other languages where this can be done... in literally, two lines of code (see (L1) and (L2) in above code) and not having to do a lot of formatting and editing.)
(I've done it before - there is another language where all you'd need is L1 and L2...)
================================================================
It is unfortunate that SQL Server will not do this without going to a decent amount of effort...
first write your SQL then
test it to make sure it does, in fact, work then
frame each line with tick marks and then escape your ticks that are now inside THOSE tick marks
declare the variable
set the variable to the sql statement you ticked above
(I may be missing some additional steps)
Oh, and then, if you ever need to maintain it
you need to either, be very careful and just edit it right there, as is, and hope you get it all just right -or- you may have saved a copy of it... un-ticked and un-variablized so you can edit the "real" sql and then when you're done you can RE DO these steps... again.
I think you want this:
DECLARE #vTableName table(TableName varchar(50))
insert into #vTableName
SELECT TableName FROM qms_Types WHERE Id = 1
SELECT * FROM #vTableName
The only way you can do this is through Dynamic SQL which refers to the practice of creating a T-SQL text and executing it using the sp_executesql (or simply exec)
Here is a helpful link about dynamic sql The Curse and Blessings of Dynamic SQL.
You should really think whether or not this is a case for dynamic sql or if there is another way for you to perform this operation.