I have a hierarchyid column defined on a table in SQL Server 2008
Let us say that in the first row, the hierarchyid is '/1/7/1/'
Let us say that in the second row, the hierarchyid is '/1/10/1/'
If I sort by hierarchyid ASC , then I will see the second row, and then the first row. (The sorting will be sort by String, and '10'<'7')
However I have (for compatability reasons with a different system) a wish to see the first row first, and then the second row (I.e. sort by int, and 7<10)
I have solved the problem, by defining a second hierarchyid column, and then setting it to be the same as the first hierarchyid column, but replacing all inside slashes with dots, and then doing a sort by this.
I just wondered if there was a more elegant way.
I know this is a fairly old question, but it was first result in Google so thought I'd add an actual answer in case someone else comes across this. Without seeing the SQL being used it's hard to be 100% but I suspect that the OP is returning the hierarchy Id as a string and sorting on that rather than sorting on the hierarchy id itself:
EG..
declare #results table (Id int, Hierarchy hierarchyId)
-- :
-- Add your data here
-- :
-- This will not work as it's ordering a string
select Id, Hierarchy.ToString() as SortOrder from #results order by SortOrder
-- This will work as it's ordering the hierarchy id
select Id, Hierarchy.ToString() as SortOrder from #results order by Hierarchy
you would need to isolate whats between the two "/" and order by it.
you can use this function: http://www.sqlusa.com/bestpractices2005/nthindex/
to get the nth Index on a string, so
declare #aux_str varchar(50)
set #aux_str='/1/7/3/'
select dbo.fnNthIndex(#aux_str,'/',2)
returns 3. Them you have to find out the position of the third "/" and get what's between it.
Its not hard, but its quite a lot of work
Related
I have a MySQL table setup where one column's values are a string of comma-separated True/False values (1s or 0s). For example, in the column, one field's value may be "0,1,0,0,0,0,1,1,0" and another may be "1,0,0,1,1,1,0,0,0" (note: these are NOT 9 separate columns, but a string in one column). I need to QUERY the MySQL table for elements that are "true"(1) for the "nth element" of that column's value/string.
So, if I was looking for rows, with a specific column, where the 3rd element of the column's value was 1, it would produce a list of results. So, in this case, I would only be searching for "1" in the fth place (12345 = X,X,X...) of the string (X,X,1,X,X,X,X,X,X,X). How can I query this?
This is a crude example of what I am trying to do ...
"SELECT tfcolumn FROM mytable WHERE substr({tfcolumn}, 0, 5)=1"
{tfcolumn} represents the column value
5 represents the 5th position of the string
=1 represents what I need that position to equal to.
Please help. Thanks
You can't. Once you put a serialized data type into a column in SQL (like comma separated lists, or JSON objects) you are preventing yourself from performing any query on the data in those columns. You have to pull the data in a different way and then use a program like python, VB, etc to get the comma separated values you are looking for.
Unless you want to deal with trying to make this mess of a query work...
I would recommend changing your table structure before it's too late. Although it is possible, it is not optimized in a format that a DBMS recognizes. Because of that the DBMS will spend a significant amount of time going through every record to parse the csv values which is something that it was not meant to be doing. Doing the query in SQL will take as much time (if not more time) than just pulling all the records and searching with a tool that can do it properly.
If the column contains values exactly like the ones you posted, then the Nth element is at the 2 * N - 1 position in the comma separated list.
So do this:
SELECT tfcolumn
FROM tablename
WHERE substr(tfcolumn, 2 * 5 - 1, 1) = '1'
Replace 5 with the index that you search for.
See the demo.
Or remove all commas and get the Nth char:
SELECT tfcolumn
FROM tablename
WHERE substr(replace(tfcolumn, ',', ''), 5, 1) = '1'
See the demo.
Try this
if substring_index(substring_index('0,1,0,0,0,0,1,1,0',',',3),',',-1)='1'
The first argument can be your column name. The second argument (',') tells the function that the string is comma-separated. The third argument takes the first 3 elements of the string. So, the output of inner substring_index is '0,1,0'.
The outer substring_index has -1 as the last argment. So, it starts counting in reverse direction & takes only 1 element starting from right.
For example, if the value in a particular row is '2,682,7003,14,185', then the value of substring_index(substring_index('2,682,7003,14,185',',',3),',',-1) is '7003'.
I am looking for a way, inside a TSQL SELECT statement, to repeat a string literal N times, where N is in integer that I select (or calculate) from columns on a table.
What I am doing, specifically, is parsing a hierarchical tree structure into nested HTML unordered lists. So, suppose we're very deep in the tree, but the next entry is very shallow. We need to close a bunch of open <ul> and <li> tags from higher up in the tree. So what I have done (but I feel is too kludgy) is:
select case Depth-Next_Depth
when -1 then ''
when 0 then ''
when 1 then '</ul></li>'
when 2 then '</ul></li></ul></li>'
when 3 then '</ul></li></ul></li></ul></li>'
...
end
from MyTable
I know that I could create a scalar function like ReturnClosingTags(#N int) but I don't want to add another object to the database for this. I want it to all happen in the select statement so I don't have to further modify the DB schema.
I also know that my whole approach here (writing the code myself to parse my tree into HTML) may be harebrained, so feel free to comment with an alternative... but I am interested in the question for its own sake, so even if you say "duh just use .NET library XYZ for this" I'd like to know if there's an answer to this little SQL puzzle.
SQL Server happens to have this function built-in: replicate().
select replicate('</ul></li>', depth)
Because it returns the same type as the first argument, you might want to cast() the value to varchar(8000) or varchar(max) first.
In my database I have table with a name column containing grades, like 1. grade, 2. grade, and so on. When the numbers have reached 10 or more, the sorting doesn't work as I would like, as 10. grade comes before 2. grade in the sorted recordset. I know this is because string sorting is different from integer sorting. The question is how to sort these strings in a numeric way.
Because the grade-records are a part of a tree buildt with the ancestry plugin, I have to put the whole sorting code inside :order => "(some code that sorts the results)".
I have tried :order => "CAST(SUBSTRING_INDEX(name, '.') AS SIGNED)". But this doesn't work.
I use SQLite in my development environment and MySQL in the production environment.
try this:
replace the constant vale '. grade' of your column with empty string, then you get the numeric value. cast the same to int
order by cast(replace(name,'. grade','') as int)
EDIT:
as per your comment if its not 'grade' always, then try
order by cast(left(name,LOCATE('.',name,1)-1) as UNSIGNED)
SQL fiddle demo
I am new to SQL and I have several large database with upper case first and last names that I need to convert to proper case in SQL sever 2008.
I am using the following to do this:
update database
Set FirstNames = upper(substring(FirstNames, 1, 1))
+ lower(substring(FirstNames, 2, (len(FirstNames) - 1) ))
I was wondering if there was any way to adapt this so that a field with two first names is also updated (currently I make the change and then go through and manually change the second name).
I have looked over the other answers in this field and they all seem quit long, compared to the query above.
Also is there any way to assist with converting the Mc suranmes ( I will manually change the others)? MCDONALD to McDonald, again I am just using the about query but replacing the FirstNames with LastName.
This is probably best done outside of SQL. However, if there is a requirement to do it on the server or if speed isn't an issue (because it will be an issue so you need to figure out if you care), the way you are going about it is probably the best way of doing so. If you want, you could create a UDF that puts all of the logic in one area.
Here is some code I came across (with attribution and more information below it):
CREATE FUNCTION dbo.fCapFirst(#input NVARCHAR(4000)) RETURNS NVARCHAR(4000)
AS
BEGIN
DECLARE #position INT
WHILE IsNull(#position,Len(#input)) > 1
SELECT #input = Stuff(#input,IsNull(#position,1),1,upper(substring(#input,IsNull(#position,1),1))),
#position = charindex(' ',#input,IsNull(#position,1)) + 1
RETURN (#input)
END
--Call it like so
select dbo.fCapFirst(Lower(Column)) From MyTable
I got this code from http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=37760 There is more information and other suggestions in this forum as well.
As for dealing with cases like the McDonald, I would suggest one of two ways to handle this. One would be to put a search in the above UDF for key names ('McDonald', 'McGrew', etc.) or for patterns (the first two letters are Mc then make the next one capital, etc.) The second way would be to put these cases (the full names) in a table and have their replacement value in a second column. Then simply do a replace. Most likely, however, it will be easiest to identify rules like Mc then capitalize instead of trying to list every last-name possibility.
Don't forget you may want to modify the above UDF to include dashes, not just spaces.
Maybe this is too long but it is very easy and can be adapted for -, ', etc:
UPDATE tbl SET LastName = Case when (CharIndex(' ',lastname,1)<>0) then (Upper(Substring(lastname,1,1))+Lower(Substring(lastname,2,CharIndex(' ',lastname,1)-1)))+
(Upper(Substring(lastname,CharIndex(' ',lastname,1)+1,1))+
Lower(Substring(lastname,CharIndex(' ',lastname,1)+2,Len(lastname)-(CharIndex(' ',lastname,1)-1))))
else (Upper(Substring(lastname,1,1))+Lower(Substring(lastname,2,Len(lastname)-1))) end,
FirstName = Case when (CharIndex(' ',firstname,1)<>0) then (Upper(Substring(firstname,1,1))+Lower(Substring(firstname,2,CharIndex(' ',firstname,1)-1)))+
(Upper(Substring(firstname,CharIndex(' ',firstname,1)+1,1))+
Lower(Substring(firstname,CharIndex(' ',firstname,1)+2,Len(firstname)-(CharIndex(' ',firstname,1)-1))))
else (Upper(Substring(firstname,1,1))+Lower(Substring(firstname,2,Len(firstname)-1))) end;
Tony Rogerson has code that deals with:
double barrelled names eg Arthur Bentley-Smythe
Control characters
I haven't used it myself though...
I want to check in mysql if a column is either blank, ie '', or 0.
Is there a way to do this with one condition?
Like
WHERE order_id > ''
or
WHERE order_id != ''
Would either of these work, or is there a different solution?
This is more a question of data quality. In a well designed database, there should be a fairly clear-cut difference between '' and 0.
If you're being vague about it, there are quite a lot of values that could be interpreted as "blank" in addition to these two. NULL is the obvious one, but what about white space? Or a string containing 0.00, or even if you're looking for a numeric value, any non-numeric string.
Ideally, the data should be stored in a format that matches the type of data it is supposed to hold - for example, if you're expecting a numeric field, it should be an int, or another numeric type, depending on exactly what you want to store. That way, it can never contain a string value, so you would never need to check for it.
If you can't change the type in the DB itself, the next best solution is to cast the value as that data type you are expecting in the select query. eg:
SELECT CAST(myfield as int) as myfieldnum FROM table where myfieldnum != 0
See the MySQL manual for more info: http://dev.mysql.com/doc/refman/5.0/en/cast-functions.html
However, in the end, it does depend on exactly what you are expecting the data field to contain, and how you want to react to different types of content.
Does this qualify as one condition?
... WHERE order_id IN ('0', '');
I experimented a bit and it seems the answer is:
WHERE order_id != 0
This will show results where order_id is not 0 and also not blank
why dont u use a smiple query where both of ur conditions are going to be tested
select * from tbl_name where order_id=' ' or order_id = 0
try this it will work