Ordering a Union Query in MS Access SQL - ms-access

OK I have a particularly nasty union ordering problem so any help would be appreciated.
The scenario is this:
Member Table with the following records (actual data):
REI882
YUI987
POBO37
NUBS26
BTBU12
MZBY10
TYBW54
(These are listed in the order I want them back from my query.)
There are a number of business rules about the construction of these MemberIDs which I believe are unrelated to the sort. They're historic and set in stone. I'm stuck with them. They indicate seniority of the member.
The ordering is done from the last 4 characters in the ID, ascending. The first two characters of the ID are completely meaningless as far as the sort is concerned.
So the topmost possible record is ??A001 (most senior) and the lowest possible record is ??ZZ99 (least senior).
When I query my member table the list I get back must display most senior at top... Obviously a standard sort does not work. This is what I have to date:
The first of these queries deals with sorting members whose ID only has 1 leading letter. The second deals with those with 2 leading letters.
SELECT * FROM (
SELECT Member.ID
FROM Member
WHERE (((IsNumeric(Mid([Member.ID],4,1)))=-1)) **check the 4th character is a digit
ORDER BY (Mid([Member.ID],3,1)), (Mid([Member.ID],4,1)), (Mid([Member.ID],5,1)), (Mid([Member.ID],6,1))
) t1
UNION
SELECT * FROM (
SELECT Member.ID
FROM Member
WHERE (((IsNumeric(Mid([Member.ID],4,1)))=0)) **check the 4th character is a letter
ORDER BY (Mid([Member.ID],3,1)), (Mid([Member.ID],4,1)), (Mid([Member.ID],5,1)), (Mid([Member.ID],6,1))
) t2
But I get CRAZY results with the union! If I run each of the selects individually - no problem my funky (heavily reliant on some nasty string manipulation in access!) sort works exactly as I want it.
I understand this is pretty complicated but I hope I've explained it clearly and that someone is up for some kudos for figuring it out!!!
edit: The result from my query is seemingly random:
YUI987
MZBY10
NUBS26
BTBU12
REI882
POBO37
TYBW54

ORDER BY in a SELECT statement that UNION with another SELECT is not correct.
See Specifying a conditional order here
You can use this:
SELECT ID FROM(
(SELECT Member.ID,1 AS T,Left([Member.ID],2) AS Part1, Right([Member.ID],4) AS Part2
FROM Member
WHERE (((IsNumeric(Mid([Member.ID],3,1)))=-1)))
UNION
(SELECT Member.ID,2 AS T,Left([Member.ID],3) AS Part1, Right([Member.ID],3) AS Part2
FROM Member
WHERE (((IsNumeric(Mid([Member.ID],4,1)))=-1) and ((IsNumeric(Mid([Member.ID],3,1)))=0)))
UNION
(SELECT Member.ID,3 AS T,Left([Member.ID],4) AS Part1, Right([Member.ID],2) AS Part2
FROM Member
WHERE (((IsNumeric(Mid([Member.ID],5,1)))=-1) and ((IsNumeric(Mid([Member.ID],4,1)))=0)))
ORDER BY T,Part1,Part2)
#Justin Kirk: I don't know what is your problem exactly. But I hope it can help you

Why are you not using the RIGHT function.
Something like
SELECT ID
FROM (
SELECT ID
FROM (
SELECT Member.ID
FROM Member
WHERE (((IsNumeric(Mid([Member.ID],4,1)))=-1)) **check the 4th character is a digit
) t1
UNION
SELECT ID
FROM (
SELECT Member.ID
FROM Member
WHERE (((IsNumeric(Mid([Member.ID],4,1)))=0)) **check the 4th character is a letter
) t2
) t3
ORDER BY RIGHT(ID,4)

How about skipping the UNION?
SELECT members.ID
FROM members
ORDER BY Right([ID],3), Right(id,4)
Based on the new rules, this mess may work.
SELECT
Len(IIf([textId] Like "[a-z][a-z][0-9][0-9][0-9][0-9]",Left([textid],2),
IIf([textId] Like "[a-z][a-z][a-z][0-9][0-9][0-9]",Left([textid],3),
IIf([textId] Like "[a-z][a-z][a-z][a-z][0-9][0-9]",Left([textid],4),"_")))) AS Ln,
IIf(textId Like "[a-z][a-z][0-9][0-9][0-9][0-9]",Left(textid,2),
IIf(textId Like "[a-z][a-z][a-z][0-9][0-9][0-9]",Left(textid,3),
IIf(textId Like "[a-z][a-z][a-z][a-z][0-9][0-9]",Left(textid,4),"_"))) AS Alpha,
IIf(textId Like "[a-z][a-z][0-9][0-9][0-9][0-9]",Val(Right(textid,4)),
IIf(textId Like "[a-z][a-z][a-z][0-9][0-9][0-9]",Val(Right(textid,3)),
IIf(textId Like "[a-z][a-z][a-z][a-z][0-9][0-9]",Val(Right(textid,2)),0))) AS Numbr,
table.textid
FROM table
ORDER BY
Len(IIf([textId] Like "[a-z][a-z][0-9][0-9][0-9][0-9]",Left([textid],2),
IIf([textId] Like "[a-z][a-z][a-z][0-9][0-9][0-9]",Left([textid],3),
IIf([textId] Like "[a-z][a-z][a-z][a-z][0-9][0-9]",Left([textid],4),"_")))),
IIf(textId Like "[a-z][a-z][0-9][0-9][0-9][0-9]",Left(textid,2),
IIf(textId Like "[a-z][a-z][a-z][0-9][0-9][0-9]",Left(textid,3),
IIf(textId Like "[a-z][a-z][a-z][a-z][0-9][0-9]",Left(textid,4),"_"))),
IIf(textId Like "[a-z][a-z][0-9][0-9][0-9][0-9]",Val(Right(textid,4)),
IIf(textId Like "[a-z][a-z][a-z][0-9][0-9][0-9]",Val(Right(textid,3)),
IIf(textId Like "[a-z][a-z][a-z][a-z][0-9][0-9]",Val(Right(textid,2)),0)))

Related

MySQL - WHERE x IN ( column)

I tried something out. Here is a simple example in SQL Fiddle: Example
There is a column someNumbers (comma-seperated numbers) and I tried to get all the rows where this column contains a specific number. Problem is, the result only contains rows where someNumbers starts with the specific number.
The query SELECT * FROM myTable where 2 in ( someNumbers ) only returns the row with id 2 and not the row with id 1.
Any suggestions? Thank you all.
You are storing data in the wrong format! You should not be storing multiple values in a single string column. You should not be storing numbers as strings. Instead, you should have a junction table with one row per id and per number.
Sometimes, you just have no choice, because someone else created a really poorly designed database. For these situations, MySQL has the function find_in_set():
SELECT *
FROM myTable
WHERE find_in_set(2, someNumbers ) > 0;
The right solution, however, is to fix the data model.
While Gordon's answer is a good one, here is a way to do this with like
SELECT * FROM myTable where someNumbers like '2,%' or someNumbers like '%,2,%' or someNumbers like '%,2'
The first like checks if your array starts with the number you are looking for (2). The second one checks if 2 is within the array and the last like tests for appearance at the end.
Note that the commas are essential here, because something like '%2%' would also match ...,123,...
EDIT: As suggested by the OP it may happen that only a single value is present in the row. Consequently, the query must check this case by doing ... someNumbers = '2'
I would suggest this query :
SELECT * FROM myTable where someNumbers like '%2%'
It will select every entry where someNumbers contains '2'
Select * from table_name where coloumn_name IN(value,value,value)
you can use it

mySQL find most common starting letter for values

From a mySQL table I would like to determine the most frequent starting letter; for example if the list is:
day
book
cat
dog
apple
The expected result would ultimately allow me to determine that:
'd' is the most frequent starting letter
'd' has a count of 2
Is there a way to do this without running 26 queries, e.g.:
WHERE myWord LIKE 'a%'
WHERE myWord LIKE 'b%'
...
WHERE myWord LIKE 'y%'
WHERE myWord LIKE 'z%'
I found this SO question which makes me think I can do this in 2 steps:
If I'm not mistaken the approach would be to first build a list of all the first letters using the approach from this SO Answer something like this:
SELECT DISTINCT LEFT(word_name, 1) as letter, word_name
FROM word
GROUP BY (letter)
ORDER BY letter
which I expect would look something like:
a
b
c
d
d
... and then query that list. To do this I would store that new list as a temporary table as per this SO question, something like:
CREATE TEMPORARY TABLE IF NOT EXISTS table2 AS (SELECT * FROM table1)
and query that for Magnitude as per this SO question, something like.
SELECT column, COUNT(*) AS magnitude
FROM table
GROUP BY column
ORDER BY magnitude DESC
LIMIT 1
Is this a sensible approach?
NOTE:
As sometimes happens, in writing this question I think I figured out a way forward, as yet I have no working code. I'll update the question later with code that either works or which needs help.
In the meanwhile I appreciate any feedback, pointers, proposed answers.
Finally, I'm using PHP, PDO, mySQL for this.
TIA
For what it's worth there was an easier way, this is what I ended up with thanks to both who took the time to answer:
$stmt_common2 = $pdo->prepare('SELECT COUNT(*) as occurence,SUBSTRING(word,1,1) as letter
FROM words
GROUP BY SUBSTRING(word,1,1)
ORDER BY occurence DESC, letter ASC
LIMIT 1');
$stmt_common2->execute();
$mostCommon2 = $stmt_common2->fetchAll();
echo "most common letter: " . $mostCommon2[0]['letter'] . " occurs " . $mostCommon2[0]['occurence'] . " times)<br>";
You can achieve by using this simple query
SELECT COUNT(*) as occurence,SUBSTRING(word_name,1,1) as letter
FROM word
GROUP BY SUBSTRING(word_name,1,1)
ORDER BY occurence DESC, letter ASC
LIMIT 1

Query to select data from mysql with specific condition

In MySQL we can use this code to select rows with ID numbers (or anything else) between a list:
SELECT * FROM TABLENAME WHERE prophrases IN (1,2,3,4,5,6)
Thats OK! but if we need to search a number in a Field's value, what we can do?
For example, I have a table with a field, named 'prophases' and I saved data like this:
rowid / prophases
1 / 1,2,3,4,5,6,7,8
2 / 6,5,2,7,9,2
now, i need to check if a number like 6 is in prophrases in row #1 or not!
what can i do for that?
something like this but in correct form!
SELECT * FROM TABLENAME WHERE 6 IN prophrases
you should just use FIND_IN_SET()
SELECT rowid
FROM TABLENAME
WHERE FIND_IN_SET('6', prophrases)
This will work if you are only dealing with single digits
select * from tablename where prophrases like '%6%'
This will work if you are going to have number with more than one digit and there are no spaces between commas.
select * from tablename where prophrases like '%,6,%' or prophrases like '6,%' or prophrases like '%,6'
You need to use a like statement
SELECT * FROM TABLENAME WHERE prophrases LIKE '%6%'
However if you have multiple digit numbers that could cause some unexpected results, so you might have to amend it like
SELECT * FROM TABLENAME
WHERE prophrases LIKE '%,6,%'
OR prophrases LIKE '6,%'
OR prophrases LIKE '%,6'
The first part matches 6 in between commas, the second one matches a 6 at the beginning followed by a comma, the third matches a comma followed by a six a the end.
Storing data like that is not the best way of doing it. You are probably better off having another table that has a one-to-many relationship.

SQL string matching

I use a string for store the days of the week, something like this:
MTWTFSS. And if I search for MF (Monday and Friday) then the query must return all the strings that contain MF (for example: MWF, MTWTFS, MF, and so on).
I don't know how to do this in SQL (MySQL).
use LIKE with %-wildcard between the single characters:
SELECT * FROM table WHERE column LIKE '%M%F%';
note that this will only work if the characters are in correct order - searching for FM instead of MF won't give you any result.
you'll also need to find a way to insert the %s to your search-term, but taht shouldn't be a big problem (sadly you havn't said wich programming-language you're using).
if the characters can be in random order, you'll have to built a query like:
SELECT * FROM table WHERE
column LIKE '%M%'
AND
column LIKE '%F%'
[more ANDs per character];
SELECT * FROM yourTable WHERE columnName LIKE '%MF%'
Learn more:
http://www.sqllike.com/
Can you not just say
SELECT * FROM blah WHERE weekday LIKE "%MF%"

Regex for MySQL query

I am trying to select a field based on it meeting one of 3 criteria... and I'm not sure how to do this. I think a RegExp is probably the best method buy I'm unfamiliar with writing them.
Say I have the integer 123, I would like to match the following cases:
123 (thats 123 only with no spaces or other numbers after it)
123-10/12/2007 00:00 (thats 123 with a hyphen and a date, or actually it could be anything after the hyphen)
123_1014859 (thats 123 with an underscore, or again anything after the underscore)
Is there a way to do this using MySQL?
A regex is plausible, but it's not the best performing option. The last comparison put MySQL's regex support as being par with wildcarding the left side of a LIKE statement -- works, but the slowest of every option available.
Based on your example, you could use:
SELECT t.*
FROM YOUR_TABLE t
WHERE t.column LIKE '123-%'
OR t.column LIKE '123_%'
Another alternative, because OR can be a performance issue too, would be to use a UNION:
SELECT a.*
FROM YOUR_TABLE a
WHERE a.column LIKE '123-%'
UNION ALL
SELECT b.*
FROM YOUR_TABLE b
WHERE b.column LIKE '123_%'
UNION ALL will return all results from both tables; UNION removes duplicates, and is slower than UNION ALL for that fact.
select * from foo where bar regexp '^123-|_'
(not tested)
I would avoid using regex inside a SQL statement. Someone can correct me if I am wrong, but MySQL has to use another engine to run the regex.
SELECT * FROM table
WHERE field like "123"
OR field LIKE "123-%"
OR field like "123_%";