MSAccess 2007 SQL
I am writing a user search dropdown for values in a table column.
If the user types 'xyz' into the field, I want to find all rows where the search column starts-with or contains 'xyz'. But I want those rows where the column starts with 'xyz' to sort first, followed by those rows where that column contains 'xyz'. I know how to use a LIKE clause with wildcards to find the required rows, the question is on how to get the result set returned in the order below.
For example, if my search column contains:
abcxyz
mno
xyzabc
xyzmon
2xyz
abcxyzruf
zxyz
I want the query to return all rows where column contains 'xyz' in this order:
xyzabc
xyzmon
2xyz
abcxyz
abcxyzruf
zxyz
What is the best, most efficient, only - way to make this happen with SQL in MSaccess 2007?
You can use instr():
order by instr(col, "xyz")
Note: This assumes that all strings have "xyz" in them. If not, the non-matches will (unintuitively) come first. However, for your sample data, all the values do have "xyz".
EDIT:
For your revised version:
order by iif(col like "xyz*", 1, 2), col
Gordon's answer got me on the right track.
Order By iif(instr(col, 'xyz')=1, instr(col, 'xyz'), col), col
That does it!!! Thanks so much Gordon.
The second col for Order By forces the starting-with sub-group to also sort alphabetically.
Related
I have one table with rows and each row has a column that contains a field name (say raw1 - 'Number001', raw2-'ShortChar003', etc). In order for me to get that value of these fields I have to use a second table; this table has 1 raw with many columns (number001, Number002, ShortChar003, etc).
How can I extract the value?
Good Question..You can use lookup function
=Lookup(Fields!CityColumn.Value, Fields!CityColumn.Value, Fields!CountColumn.Value, "Dataset1")
Or you might have to use string functions..ex LEFT, Substring, Right same like SQL.If possible pls post some data of both tables, I will explain in detail
Correction - I only need to Pick the WORK value every result set in the column will contain comma seperated values like below..
"SICK 0.08, WORK 0.08" or "SICK 0.08,WORK 0.08"
I only need to pick WORK 0.08 from this.
I am quite new to SQL
I am using the following script to get some results;
select Work.Work_summary, Work.emp_id
from Work
all work fine. but the first column has values like the following :
WORK 08.57, SICK 08.56 (Some columns)
SICK 07.80, WORK 06.80 , OT 02.00 (Some columns)
How can i only retrieve the column with only the WORK% value, if there is no WORK value the results shall be empty.
select Work_summary, emp_id
from Work
where Work_summary like '%WORK%'
This will return the rows in the Work table where Work_summary column contains the word WORK. See the documentation for more details.
Contains is faster than like.
SELECT Work_summary, emp_id FROM Work WHERE CONTAINS(Work_summary, 'WORK');
then use: this will give only the result where work summary contains work content.
select Work.Work_summary, Work.emp_id
from Work where contains(work.Work_summary ,'work');
select replace(Work_summary,",","") as work_summary
from Work
where upper(Work_summary) like '%WORK%'
Use:
The user searches for a partial postcode such as 'RG20' which should then be displayed in a specific order. The query uses the MATCH AGAINST method in boolean mode where an example of the postcode in the database would be 'RG20 7TT' so it is able to find it.
At the same time it also matches against a list of other postcodes which are in it's radius (which is a separate query).
I can't seem to find a way to order by a partial match, e.g.:
ORDER BY FIELD(postcode, 'RG20', 'RG14', 'RG18','RG17','RG28','OX12','OX11')
DESC, city DESC
Because it's not specifically looking for RG20 7TT, I don't think it can make a partial match.
I have tried SUBSTR (postcode, -4) and looked into left and right, but I haven't had any success using 'by field' and could not find another route...
Sorry this is a bit long winded, but I'm in a bit of a bind.
A UK postcode splits into 2 parts, the last section always being 3 characters and within my database there is a space between the two if that helps at all.
Although there is a DESC after the postcodes, I do need them to display in THAT particular order (RG20, RG14 then RG18 etc..) I'm unsure if specifying descending will remove the ordering or not
Order By Case
When postcode Like 'RG20%' Then 1
When postcode Like 'RG14%' Then 2
When postcode Like 'RG18%' Then 3
When postcode Like 'RG17%' Then 4
When postcode Like 'RG28%' Then 5
When postcode Like 'OX12%' Then 6
When postcode Like 'OX11%' Then 7
Else 99
End Asc
, City Desc
You're on the right track, trimming the field down to its first four characters:
ORDER BY FIELD(LEFT(postcode, 4), 'RG20', 'RG14', ...),
-- or SUBSTRING(postcode FROM 1 FOR 4)
-- or SUBSTR(postcode, 1, 4)
Here you don't want DESC.
(If your result set contains postcodes whose prefixes do not appear in your FIELD() ordering list, you'll have a bit more work to do, since those records will otherwise appear before any explicitly ordered records you specify. Before 'RG20' in the example above.)
If you want a completely custom sorting scheme, then I only see one way to do it...
Create a table to hold the values upon which to sort, and include a "sequence" or "sort_order" field. You can then join to this table and sort by the sequence field.
One note on the sequence field. It makes sense to create it as an int as... well, sequences are often ints :)
If there is any possibility of changing the sort order, you may want to consider making it alpha numeric... It is a lot easier to insert "5A" between "5 and "6" than it is to insert a number into a sequence of integers.
Another method I use is utilising the charindex function:
order by charindex(substr(postcode,4,1),"RG20RG14RG18...",1)
I think that's the syntax anyway, I'm just doing this in SAS at the moment so I've had to adapt from memory!
But essentially the sooner you hit your desired part of the string, the higher the rank.
If you're trying to rank on a large variety of postcodes then a case statement gets pretty hefty.
I have a totals query (one where I clicked the totals button, and it has "group by" columns) in Access 2007. Most of the columns are fine... group by columns, max columns, min columns, etc. For some of them though, I want to extract only the last non-blank (not "" or null) value of a string column.
Here's a sample of what my SQL looks like:
SELECT Min(Duplicates.AttendedODBefore) AS AttendedODBefore,
Min(Duplicates.ContactByPost) As ContactByPost,
Last(Duplicates.PlannedStart) As PlannedStart,
Min(Duplicates.AccessibilityRequirements) AS AccessibilityRequirements,
Last(Duplicates.UcasNumber) As UcasNumber
-- ^^^^
FROM DuplicateStudents As Duplicates
GROUP BY
Duplicates.ID
The expression highlighted is the one I want changing to the last non-blank field. Is there an Access-specific or plain SQL expression which will do this?
Edit: Turns out that Min() and Max() work on string values and ignores null values, taking the first and last values alphabetically. It's not perfect, because it doesn't guarantee that the value selected is the last one, but it's better than just a load of nulls which is what using Last() might give.
Access seems resistant to the idea of returning the last non-null value in a query using GROUP BY. Even if your FROM clause were modified to be something like
FROM (
SELECT allfieldsyouneed
FROM DuplicateStudents
ORDER BY PlannedStart
) AS SortedDuplicates
and the rest of your query were modified to use SortedDuplicates instead, Access doesn't seem to return the last value based on the order you specify. I tested on a table with exactly one blank row and specific orders that I could verify (both an auto-increment field and a value that I checked by using Min and Max), and Access chose to return some other value as Last.
Based on your comment it seems like your definition of "Last" is: the most recently added record, based on an auto-incrementing ID. As such, some form of the following should work (it uses a subquery to return the most recent non-null UcasNumber):
SELECT Min(Duplicates.AttendedODBefore) AS AttendedODBefore,
Min(Duplicates.ContactByPost) As ContactByPost,
Last(Duplicates.PlannedStart) As PlannedStart,
Min(Duplicates.AccessibilityRequirements) AS AccessibilityRequirements,
(SELECT TOP 1 D.UcasNumber FROM Duplicates AS D
WHERE D.UcasNumber Is Not Null
ORDER BY D.ID DESC) As UcasNumber
FROM DuplicateStudents As Duplicates
Suppose I want to order the records order by a field (string data type) called STORY_LENGTH. This field is a multi-valued field and I represent the multiple values using commas. For example, for record1, its value is "1" and record2 its value is "1,3" and for record3 its value is "1,2". Now when, I want to order the records according to STORY_LENGTH then records are ordered like this record1 > record3 > record2. Its clear that STORY_LENGTH data type is string and order by ASC is ordering that value considering it as string. But, here comes the problem. For example, when record4="10" and record5="2" and I try to order it looks like record4 > record5 which obviously I don't want. Because 2 > 10 and I am using a string formatted just because of multiple values of the field.
So, anybody, can you help me out of this? I need some good idea to fix.
thanks
Multi-values fields as you describe mean your data model is broken and should be normalized.
Once this is done, querying becomes much more simple.
From what I've understood you want to sort items by second or first number in comma separated values stored in a VARCHAR field. Implementation would depend on database used, for example in MySQL it would look like:
SELECT * FROM stories
ORDER BY CAST(COALESCE(SUBSTRING_INDEX(story_length, ',', -1), '0') AS INTEGER)
Yet it is not generally not good to use such sorting for performance reasons as sorting would require scanning of whole table instead of using index on field.
Edit: After edits it looks like you want to sort on first value and ignore value(s) after comma. As according to some comment above changes in database design are not an option just use following code for sorting:
SELECT * FROM stories
ORDER BY CAST(COALESCE(NULLIF(SUBSTRING_INDEX(story_length, ',', 1), ''), '0') AS INTEGER)