random sorting each time query is run - ms-access

in an ms-access database i have a table
num weight
1 12
4 13
2 13
6 9
7 13
how can i write a query which will sort the table according to weight in descending order . but the numbers 4, 2 and 7 have same weight (13) , so they must be sorted randomly each time query is run.
any help appreciated.

Normally, your SQL would contain a random function of some sort (it looks like Access has the rnd() function for this).
So you could use:
select num, weight, rnd(num)
from tbl
order by weight desc, 3
This will let you see r for testing purposes. In a real query, you might just want to use something like:
select num, weight
from tbl
order by weight desc, rnd(num)
From this page:
When value is greater than 0, Rnd() returns the next random number.
When value is less than 0, Rnd() returns the same random number, based on value. If value occurs only once, you won’t notice this behavior. Access also resets seed, which means the sequence starts all over again.
When value is equal to 0, Rnd() returns the most recently generated random number
Update 1: I'm unsure as to whether rnd() is executed once in the following queries or once per row - the docs aren't clear. Comments seem to indicate the same results are being received for all rows which indicates it may be the latter. It may be that changing it to rnd(num) or rnd(abs(num)+1) will fix that problem. I'll have to check when I get to a box with Access installed.
Update 2: I've now tested this in Access 2007 and it does indeed give the same random value for every row when you use rnd(1). It does give a different value for rnd(num) each time you run the query and the individual rows get different values. So the query you need is:
select num, weight from tbl order by weight desc, rnd(num);
If you create a table with two Number fields and then run that query over it, you'll see that continual refreshing (with F5) will swap around the 2, 7 and 4 rows at random but leave the 1 and 6 rows in the same place since the weights of the first three are all 13 and the weights of the last two are 12 and 9 respectively.
I've updated the queries above to match this new information.

I think this will do the trick...
ORDER BY weight, Rnd()

When using RND() in Access Database Engine SQL from outside of the Access UI, the same sequence of random numbers will be used by each session (there is no native support for VBA's Randomize).
For example, connect to the source then execute SELECT RND(); three times in succession, you will get the following values:
0.705547511577606
0.533424019813538
0.579518616199493
Close the connection, connect to the source again then execute the same query again three times you will get the same three values as above in the same order.
In the knowledge that these values are predictable, we can demonstrate that a different value for RND() is used each time it is referenced. Consider this query:
SELECT RND()
FROM T
WHERE RND() > CDBL(0.6);
We know the first value in a new session will be 0.705547511577606, therefore the expression
RND() > CDBL(0.6)
will evaluate TRUE. However, the value 0.533424019813538 is repeated for every row in table T, a value which does not satisfy the WHERE clause! So it is clear that the value of RND() in the WHERE clause is different from the value in the SELECT clause. The full code is posted below.
Note I wondered if it may be possible to use the least significant portion of CURRENT_TIMESTAMP value generate a random number that could be used consistently through the scope of a single query and not be predictable for a session as RND() is. However, the Access Database Engine does not support it and its closest analogy, the NOW() function, does not have enough granularity to be useful :(
Sub jmgirpjpo()
On Error Resume Next
Kill Environ$("temp") & "\DropMe.mdb"
On Error GoTo 0
Dim cat
Set cat = CreateObject("ADOX.Catalog")
With cat
.Create _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & _
Environ$("temp") & "\DropMe.mdb"
With .ActiveConnection
.Execute "CREATE TABLE T (T INT);"
.Execute "INSERT INTO T VALUES (1);"
.Execute "INSERT INTO T VALUES (2);"
.Execute "INSERT INTO T VALUES (3);"
Dim rs
Set rs = .Execute("SELECT RND() FROM T WHERE RND() > CDBL(0.6);")
MsgBox rs.GetString
End With
End With
End Sub

Related

Missing values in a query

I encounter some strange results in the following query :
SET #indi_id = 768;
SET #generations = 8;
SELECT num, sosa, seq, len, dernier, ful_ful_nom
FROM fullindi
LEFT JOIN lignee_new
ON ((ful_indi_id = dernier) AND (len BETWEEN 1 AND #generations))
RIGHT JOIN numbers
ON ((sosa = num) AND (premier = #indi_id))
WHERE num BETWEEN 1 AND pow(2, #generations)
GROUP BY num
ORDER BY num;
The result looks like this :
Why the row just before a full NULL one doesn't display the existing values 'sosa', 'len', 'dernier', ful_ful_nom') but only the 'seq' value (see rows 43 and 47 in this example) ?
What am I missing?
As requested, here are data :
table lignee_new :
table fullindi :
The problem is that MySQL does really dumb things when an Aggregate function is introduced, or a GROUP BY is included, but not all of the fields are in an Aggregate Function or your GROUP BY.
You are asking it to GROUP BY num but none of the other columns in your SELECT are included in the Group BY nor are they being aggregated with a function (SUM, MAX, MIN, AVG, etc..)
In any other RDBMS this query wouldn't run and would throw an error, but MySQL just carries on. It uses the logic to decide which value it should show for each field that isn't num by just grabbing the first value it finds in it's data storage which may be different between innoDB and whatever else folks use anymore.
My guess is that in your case you have more than one record in lignee_new that has a num of 43. Since you GROUP BY num and nothing else, it just grabs values randomly from your multiple records where num=43 and displays them... which is reasonable. By not including them in an aggregate function you are pretty much saying "I don't care what you display for these other fields, just bring something back" and so MySQL does.
Remove your GROUP BY clause completely and you'll see data that makes sense. Perhaps use WHERE to further filter your records to get rid of nulls or other things you don't need (don't use GROUP BY to filter).

Mysql select, if input arguments are same dont return any rows

I have a bit of an odd mysql query I need to run.
I am passing two arguments to a WHERE clause, $source and $destination (via php). I want mysql to simply return nothing if $source and destination are the same number. Otherwise do the lookup in the DB and pull the record.
Query:
SELECT count(id) AS count
FROM approval
WHERE source=1 AND destination=2 AND approved!=0
Now this will return all rows where source is one and destination is two.
BUT! I want it it to return nothing if source and destination are the same number.
Some rows in certain cases may contain the same number, but that happens in a different potion of the code, in this specific select I want it only to perform the search if source and destination are different. I looked at comparison operators but those all seem to be checking the argument against a value in the column, rather than an argument against an argument.
I think this query does what you want
SELECT count(id) AS count
FROM approvals
WHERE source = $source AND destination = $destination AND approved <> 0
HAVING $source <> $destination;
That would be a simple matter of including:
and source <> destination
in the query. This will exclude rows where the columns are the same which, because of the other clauses, means the arguments you've provided are the same as well.
This will probably still go out to the database but it's guaranteed to return a count of zero (assuming no NULLs of course - if you want to handle those, you'll need extra clauses with IS [NOT] NULL). If you don't even want to go out to the database if your two arguments are the same, the time to do that is in your PHP code by comparing the arguments beforehand.
By way of example, the following DDL:
create table xyzzy (a int, b int);
insert into xyzzy (a,b) values (1,1);
creates a table with one row. When you execute the queries:
SELECT count(a) AS x FROM xyzzy WHERE a = 1 AND b = 1;
SELECT count(a) AS x FROM xyzzy WHERE a = 1 AND b = 1 and a <> b;
you'll get the rows 1 (equivalent to what you currently have) and 0 (equivalent to the change I've proposed).
If you really want to use the parameters instead of the columns, that will work as well:
SELECT count(a) AS x FROM xyzzy WHERE a = 1 AND b = 1 and 1 <> 1;
This also returns a count of zero and is equivalent to just tacking:
and $source <> $destination
onto your query. If the two numbers are identical, this will boil down to and false which will result in a count of zero.
So will either of:
and source <> $destination
and $source <> destination
for that matter.

Concat Column A and B as value of Column C in access

What I get on Google's search results are on creating a query.
What I am looking for is an excel like function, though I use MS Access.
How am I able to automatically get a concatenated Week & SowOrder appear on EN?
0101
0102
I use 2010 Access but 2003 format.
You can concatenate those fields in a query.
SELECT [Week], SowOrder, [Week] & SowOrder AS EN
FROM YourTable;
Then you can use the query anytime you need to see EN.
If you need to store those concatenated values in your table, you can use an UPDATE query.
UPDATE YourTable
SET EN = [Week] & SowOrder;
However, storing the values means you need to remember to execute the UPDATE again any time the Week or SowOrder values change.
Note you could use + instead of & for concatenation. The difference between those two operators is how they behave with Null:
"foo" & Null yields "foo"
"foo" + Null yields Null
I'm not sure how you'd get the leading zeros from each field to display if they are of number types, or if your data would change to '10', '11', '12'...'41','42','43.. and so on.
However, if Fields 1 and 2 are text, Field three would be a Calculated field as
=[week]&[SowOrder]
Check this, use + sign to concatenate in your case
Calculated field
Building on HansUp's answer, you probably want
SELECT [Week], [SowOrder], Format([Week],"00") & Format([SowOrder],"00") AS EN
The Format functions will force the inclusion of leading zeroes on any single-digit numbers.

What does the data in MSysQueries mean?

I've been using VBA to examine all the queries, forms, and modules in my Access 2000 database, but it can be quite tedious and slow. Recently, I decided to take a closer look at the system tables in Access, in particular, MSysQueries and MSysObjects. Can I use these tables to examine my objects in the database faster? Of course, these tables are read-only, so I can't make any modifications to the database through them without returning to VBA. What do the attributes in MSysQueries mean?
Well, I came across this post on Google groups. I did further investigation on my own tables and wanted to share a table of information that I created inspired by work already done.
Each query can take up multiple rows in the table.
The row with attribute 0 is the beginning of the query.
The row with attribute 1 indicates the type of the query.
Flag value 1 = SELECT query.
Flag value 2 = SELECT ... INTO query, or a make table query. Name1 will have the name of the table that is created.
Flag value 3 = INSERT query; Name1 will have the name of the table to insert to.
Flag value 4 = UPDATE query
Flag value 5 = DELETE query
Flag value 6 = Crosstab query (TRANSFORM)
Flag value 9 = UNION query
The rows with attribute 2 (there could be multiple) are each formal parameter of the query. The Flag column indicates the data type (i.e. "10" for dbText) and the Name1 column indicates the name of the parameter. If there are no rows with attribute 2, then the query does not have formal parameters.
The row with attribute 3 indicates the presence of UNION or DISTINCT keywords.
Flag value 0 = Nothing special
Flag value 1 = UNION ALL
Flag value 2 = SELECT DISTINCT
Flag value 3 = UNION
Flag value 8 = SELECT DISTINCTROW
Flag value 9 = Queries on master fields and child fields
The row with attribute 4 indicates if the query comes from an external database. Name1 will contain the source if attribute 4 exists.
The rows with attribute 5 (there could be multiple) indicate each table found in the query. If the query is a UNION query, the Expression field has a split on the UNION keyword and the Name2 field has a system-generated table alias. For all other tables in a query, Name1 is the name of the table and Name2 is the alias, if there is one.
The rows with attribute 6 (there could be multiple) indicate each single field or expression in the query. If there is no attribute 6 for the query, the behavior assumed is that all fields are included. The Expression field contains each field expression or name, and Name1 contains the field alias if there is one.
Flag value 0 = Value of the field or expression
Flag value 1 = The field is a column heading in a crosstab query.
Flag value 2 = The field is a row heading in a crosstab query.
The rows with attribute 7 (there could be multiple) indicate each single join "ON" expression. The Expression field contains the actual join expression. Name1 contains the first table in the join. Name2 contains the second table in the join.
Flag value 1 = Inner Join
Flag value 2 = Left Join
Flag value 3 = Right Join
The row with attribute 8 contains the whole WHERE clause in the Expression field. If there is no where clause, attribute 8 is omitted from the query.
The rows with attribute 9 (there could be multiple) indicate each single Group By expression in the GROUP BY clause of the query. The Expression field contains each group by expression.
Flag value 0 = Value of the field or expression
Flag value 1 = The field is a column heading in a crosstab query.
Flag value 2 = The field is a row heading in a crosstab query.
The rows with attribute 11 (there could be multiple) indicate each single Order By expression in the ORDER BY clause of the query. The Expression field contains each order by expression. Name1 has "D" or "d" to indicate that the sort is done in descending order.
The row with attribute 255 is the end of the query.
I'm not exactly sure what the Order field does, but I did find that it is not Null, and though it sometimes has a value of an empty string, it doesn't always have that value. Empty strings occur on attributes 5, 6, 7, and 9, but it is not always an empty string for those attributes.
Thanks to #Bobort great explanations, I was able to create a query that lists all queries in current database, with their input tables/queries, query type, and target table (for action queries).
I thought I could share that here.
SELECT MSysObjects.Name AS queryName,
Mid("SelectMakTblAppendUpdateDeleteXtab 777777PassThUnion ",([msysqueries]![Flag]-1)*6+1,6) AS queryType,
src.Name1 AS [Input],
MSysQueries.Name1 AS Target
FROM (MSysQueries INNER JOIN MSysObjects ON MSysQueries.ObjectId = MSysObjects.Id)
LEFT JOIN (select * from MSysQueries WHERE Attribute = 5 ) AS src
ON MSysQueries.ObjectId = src.ObjectId
WHERE (((MSysObjects.Name)>"~z") AND ((MSysQueries.Attribute) =1))
ORDER BY MSysObjects.Name, src.Name1;
To use, just create a query in SQL view and paste the above code.
Further to Bobort and iDevlop's answers:
The row with attribute 1 indicates the type of the query.
Flag value 7 = DDL Query (eg CREATE TABLE...)
Flag value 9 = Pass through Query
The row with attribute 3 indicates the predicate.
Flag value 1 = All values, or UNION ALL (if a UNION query)
Flag value 4 = WITH OWNERACCESS OPTION
Flag value 16 = TOP N
Flag value 48 = TOP N PERCENT
The rows with attribute 5 (there could be multiple) indicate each FROM table/query found in the query
Expression contains the FROM source, or the SELECT statement if a UNION query
The row with attribute 10 contains the whole HAVING clause in the Expression field. If there is no HAVING clause, attribute 10 is omitted from the query.
The Order field is a BIG-ENDIAN binary value that contains an array of 4 bytes (binary fields can be added with VBA, but cannot be added using the UI, unless you copy and paste from a binary field in a system table.) However, in most databases, in the MSysQueries table, you're unlikely to encounter binary values greater than 255, so you can shortcut the conversion to a byte by inspecting the byte at index 3. For example:
Sub EnumOrder()
Dim rst As Recordset
Set rst = CurrentDb.OpenRecordset( _
" SELECT * FROM MSysQueries " & _
" WHERE Attribute = 6 " & _
"ORDER BY ObjectId Asc, [Order] Asc")
With rst
Do While Not .EOF
Debug.Print .Fields("ObjectId"), .Fields("Order")(3)
.MoveNext
Loop
.Close
End With
End Sub
Cumulative values occur for Attribute 3. So additional items include:
Flag 12 SELECT DISTINCT.... WITH OWNERACCESS OPTION
Flag 18 SELECT DISTINCT TOP (i.e. 2+16)
Flag 24 SELECT DISTINCTROW TOP (i.e. 8+16)
Flag 50 SELECT DISTINCT TOP PERCENT (i.e. 2+48)
Flag 56 SELECT DISTINCTROW TOP PERCENT (i.e. 8+48)
I have written an extended article about the workings of the MSysQueries table. See How Access stores queries.

IsNumeric in SQL Server JOIN

My problem seems to be very simple but I'm stuck here. I have a table which has an "nvarchar" column called "SrcID" and I store both numbers and strings in that. Now, when I try to check for "IsNumeric" on that column in a "Join" condition, something like below,
ISNUMERIC(SrcID) = 1 AND SrcID > 15
I am getting the following error:
Msg 245, Level 16, State 1, Line 47
Conversion failed when converting the nvarchar value 'Test' to data type int.
Amazingly, when I remove the check "SrcID > 15", my query is running properly. Should I include anything else in this statement?
Please help me in fixing the issue. Thanks in advance!!
You can't count on the order in which a database will evaluate filtering expressions. There is a query optimizer that will evaluate your SQL and build a plan to execute the query based on what it perceives will yield the best performance.
In this context, IsNumeric() cannot be used with an index, and it means running a function against every row in the table. Therefore, it will almost never provide the best perceived performance. Compare this with the SrcID > 15 expression, which can be matched with an index (if one exists), and is just a single operator expression even if one doesn't. It can also be used to filter down the number of potential rows where the IsNumeric() function needs to run.
You can likely get around this with a view, a subquery, a CTE, a CASE statement, or a computed column. Here's a CTE example:
With NumericOnly As
(
SELECT <columns> FROM MyTable WHERE IsNumeric(SrcID) = 1
)
SELECT <columns> FROM NumericOnly WHERE SrcID > 15
And here's a CASE statement option:
SELECT <columns> FROM MyTable WHERE CASE WHEN IsNumeric(SrcIC) = 1 THEN Cast(SrcID As Int) ELSE 0 END > 15
The filters in a WHERE clause are not evaluated in any particular order.
This is a common misconception with SQL Server - the optimizer will check whichever conditions it thinks it can the fastest/easiest, and try to limit the data in the most efficient way possible.
In your example, you probably have an index on SrcID, and the optimizer thinks it will be quicker to FIRST limit the results to where the SrcID > 15, then run the function on all those rows (since the function will need to check every single row otherwise).
You can try to force an order of operations with parentheses like:
WHERE (ISNUMERIC(SrcID) = 1) AND SrcID > 15
Or with a case statement:
WHERE CASE WHEN ISNUMERIC(SrcID) = 1 THEN SrcID > 15 ELSE 1=0 END