GO: Obtain various query results in if else block based on parameters number - variables

I am using go-mysql-driver to make queries to my database.
I have a function In which I am passing id and warehouseId.
Now I am modifying my mysql query based on if warehouseId value is 0 or not.
The problem is the parameters that I pass in db.Query().
Following is my mysql query where I am appending additional query if warehouseId is not 0.
query := "select id,description from offers inner join offer_entities on offers.id = offer_entities.offer_id where offer_entities.entity_id = ?"
if warehouseId != 0 {
query += `and offer_entities.warehouse_id = ? `
}
query += `group by offer_id`
I parse it like this:
if warehouseId != 0 {
rows, err := db.Query(query, variantId, warehouseId)
} else {
rows, err := db.Query(query, variantId)
}
However, the problem is when I run it, I get an error undefined: rows. I know that it is because rows should be defined outside the if-else conditions. But I don't understand how to define rows outside if-else or
If there is any other way I could achieve my requirements.
How should I tackle this problem.
Thanks in advance.

the problem is because of variables are defined in the scope in which they are declared.
The difference between = and := is that = is just assignment and := is used for assignment and declaration
for example
rows := 1
//it basically means
var rows int
rows = 1
what you want is to declare rows outside the if-else and then use them, will solve the problem.

Scope visibility
Each block has itself visibility scope. A general rule is visible from inner, invisible from outer. It means you can see variables from superior scope in subject scope but not vise versa.
I believe you use rows declared in if statement out of the block, so it doesn't exist there.
var err error
var rows string
if warehouseId != 0 {
rows, err := db.Query(query, variantId, warehouseId)
} else {
rows, err := db.Query(query, variantId)
}
fmt.Println(rows) // It is now possible to use `rows` outside of the block
Declaration styles
var name <type> is a common declaration way. The variable with typed nil value will be declared.
name := <value of type> is a short declaration form. It will declare a variable of a type and assign a value to it at the same time. Allowed only in functions.

Related

use associate array total value count Lua

i want to count the data type of each redis key, I write following code, but run error, how to fix it?
local detail = {}
detail.hash = 0
detail.set = 0
detail.string = 0
local match = redis.call('KEYS','*')
for i,v in ipairs(match) do
local val = redis.call('TYPE',v)
detail.val = detail.val + 1
end
return detail
(error) ERR Error running script (call to f_29ae9e57b4b82e2ae1d5020e418f04fcc98ebef4): #user_script:10: user_script:10: attempt to perform arithmetic on field 'val' (a nil value)
The error tells you that detail.val is nil. That means that there is no table value for key "val". Hence you are not allowed to do any arithmetic operations on it.
Problem a)
detail.val is syntactic sugar for detail["val"]. So if you expect val to be a string the correct way to use it as a table key is detail[val].
Possible problem b)
Doing a quick research I found that this redis call might return a table, not a string. So if detail[val] doesn't work check val's type.

Ordering results dynamically in marklogic

So, Here is my question -
I want to order a list based off of a set of variables that determine the sorting fields and the order
In essence I need to do "order by" dynamically.
EG:
declare function getSearchResults(
$query as cts:query,
$sort as xs:string*,
$direction as xs:string*,
) as element()* {
let $results :=
cts:search(/*, $query)
let $sortFields := fn:tokenize($sort, "\|")
let $dec := $direction = 'desc' or $direction = 'descending'
let $sorted := sortByFields($results, $sort,$dec)
return $sorted
};
declare private function sortByFields ($results, $sortFields, $dec)
{
let $asc := fn:not($dec)
for $i in $results
order by
if ($sortFields[1]='id' and $asc) then $i//ldse:document/#id else (),
if ($sortFields[1]='id' and $dec) then $i//ldse:document/#id else () descending,
if ($sortFields[1]='title' and $asc) then $i//title else (),
if ($sortFields[1]='title' and $dec) then $i//title else () descending
return if (fn:count($sortFields) > 1 ) then (sortByFields($i,$sortFields[2 to fn:count($sortFields)],$dec)) else ($i)
};
This method will not work because it has to sort multiple times, and won't preserve the sort order each iteration.
I also tried this:
let $sortFields := fn:tokenize($sort, "\|")
let $dec := $direction = 'desc' or $direction = 'descending'
let $asc := fn:not($dec)
for $i in $results
for $j in 1 to fn:count($sortFields)
order by
if ($sortFields[$j]='id' and $asc) then $i//ldse:document/#id else (),
if ($sortFields[$j]='id' and $dec) then $i//ldse:document/#id else () descending,
if ($sortFields[$j]='title' and $asc) then $i//title else (),
if ($sortFields[$j]='title' and $dec) then $i//title else () descending
return $i
but this duplicates my data. (returns it ordered by each sort Field)
I would prefer not to use xdmp:eval because of code injection, is there any way that I can do this?
Any help or suggestions would be much appreciated.
Thanks a bunch!
Several things to consider.
If you are doing ordering on the results of a cts:search() then all the results must be returned before you can order them. That means you cannot do efficient pagination. E.g. if you have a million rows and want the top 100 ... if you order it dynamically then you have to fetch 1 million rows. If this is an issue then more complex solutions are needed.
Implementation wise, this is a good case for using function items ... but to make the ascending/decending work requires static analysis. Alternatively it can always be ascending (or decending) but the value be positive/negative.
e.g.
for $r in cts:search(...)
order by myfunc($r, $criteria)
return $r
declare function myfunc( $r , $criteria ) as xs:double
{
... logic to order $r in a natural ordering of -inf ... +f..
return $ordering
};
but before digging into that, I would recommend looking at search:search() instead.
http://docs.marklogic.com/search:search#opt-sort-order
There is some very power features in this including being able to define complex ordering as an xml element.
Ultimately to do custom ordering efficiently you will probably need to create range indexes so that the ordering can be done in the server itself instead of your code. For small data sets it is not as big an issue, but when you start searching over thousands, hundreds of thousands or millions of documents you cant effectively pull them all into memory on every search (or even if you can it will be slow). Not only do the results all have to be pulled into to memory to start sorting, but the xquery code has to be evaluated for every term. Using indexes the result set can often be directly returned in the right without even loading the documents.
There are other techniques you can use such as loading the results into a map or an array, creating a self sorting tree structure, pre creating custom subsets of the data etc.
Take a look at the search:search library first ... you can even define your own search syntax for users to type in, all type and injection safe and very well optimized over years.

Berkeley DB equivalent of SELECT COUNT(*) All, SELECT COUNT(*) WHERE LIKE "%...%"

I'm looking for Berkeley DB equivalent of
SELECT COUNT All, SELECT COUNT WHERE LIKE "%...%"
I have got 100 records with keys: 1, 2, 3, ... 100.
I have got the following code:
//Key = 1
i=1;
strcpy_s(buf, to_string(i).size()+1, to_string(i).c_str());
key.data = buf;
key.size = to_string(i).size()+1;
key.flags = 0;
data.data = rbuf;
data.size = sizeof(rbuf)+1;
data.flags = 0;
//Cursor
if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
dbp->err(dbp, ret, "DB->cursor");
goto err1;
}
//Get
dbcp->get(dbcp, &key, &data_read, DB_SET_RANGE);
db_recno_t cnt;
dbcp->count(dbcp, &cnt, 0);
cout <<"count: "<<cnt<<endl;
Count cnt is always 1 but I expect it calculates all the partial key matches for Key=1: 1, 10, 11, 21, ... 91.
What is wrong in my code/understanding of DB_SET_RANGE ?
Is it possible to get SELECT COUNT WHERE LIKE "%...%" in BDB ?
Also is it possible to get SELECT COUNT All records from the file ?
Thanks
You're expecting Berkeley DB to be way more high-level than it actually is. It doesn't contain anything like what you're asking for. If you want the equivalent of WHERE field LIKE '%1%' you have to make a cursor, read through all the values in the DB, and do the string comparison yourself to pick out the ones that match. That's what an SQL engine actually does to implement your query, and if you're using libdb instead of an SQL engine, it's up to you. If you want it done faster, you can use a secondary index (much like you can create additional indexes for a table in SQL), but you have to provide some code that links the secondary index to the main DB.
DB_SET_RANGE is useful to optimize a very specific case: you're looking for items whose key starts with a specific substring. You can DB_SET_RANGE to find the first matching key, then DB_NEXT your way through the matches, and stop when you get a key that doesn't match. This works only on DB_BTREE databases because it depends on the keys being returned in lexical order.
The count method tells you how many exact duplicate keys there are for the item at the current cursor position.
You can use method DB->stat().
For example, number of unique keys in the BT_TREE.
bool row_amount(DB *db, size_t &amount) {
amount = 0;
if (db==NULL) return false;
DB_BTREE_STAT *sp;
int ret = db->stat(db, NULL, &sp, 0);
if(ret!=0) return false;
amount = (size_t)sp->bt_nkeys;
return true;
}

Why am I getting java.sql.SQLException: Operation not allowed after ResultSet closed

So I've been looking around about this problem and it seems that the problem arises when a statement tries to get multiple ResultSets.
But in the following code I get the exception, even though the executeUpdate just returns an int.
ResultSet resultsRS = statement.executeQuery("select distinct snum from shipments where quantity >= 100");
int rowCount=0;
while(resultsRS.next()){
statement.executeUpdate("UPDATE suppliers SET status = status + 5 WHERE snum = "+"\""+resultsRS.getString(1)+"\"");
rowCount++;
}
It runs one time fine, after that it gives the exception.
How would I be able to fix this?
All execution methods in the Statement interface implicitly close a statment's current ResultSet. See docs So you need to store resultSet data in a temporary array and loop through it.
Or try to use another statement for executeUpdate.
Try something like this:
ArrayList<String> tmp = new ArrayList<String>();
while(resultsRS.next()){
tmp.add(resultsRS.getString(1));
}
for (String s: tmp) {
statement.executeUpdate("UPDATE suppliers SET status = status + 5 WHERE snum = "+"\""+s+"\"");
rowCount++;
}

Sql Select - Total Rows Returned

Using the database/sql package and drivers for Postgres and Mysql I want to achieve the following. I want to be able to Select one row and know that there is either zero rows, one row, or more than one row. the QueryRow function does not achieve that, because as far as I can ascertain, it will return one row without error regardless of if there is more than one row. For my situation, more than one row may be an error, and I want to know about it. I want to create a general function to do this.I looked at creating a function that uses the Query function, but I do not know how to return the first row if there is more than one row. I want to return the fact that there is more than one row, but I also want to return the first row. To determine that there is more than one row, I have to do a Next, and that overwrites the first row. Obviously I can achieve this without creating a general function, but I want a function to do it because I need to do this in a number of placesCould someone please explain to me how to achieve this. IE. To return the first row from a function when a successful Next has been done or the Next returned nothing.
I'm using both database/sql & MySQLDriver to achieve this. You can download MySQLDriver at https://github.com/go-sql-driver/ .
I wrote execQuery function myself to get one or more rows from database. It's based on MySQL but I think it can also used to Postgres with similar implement.
Assume you have a DB table named test, and have rows named id, name, age.
Code:
var db *sql.DB // it should be initialized by "sql.Open()"
func execQuery(SQL string, args ...interface{}) (rows *sql.Rows, is_succeed bool) {
rows, err := db.Query(SQL, args...)
var ret bool
if err == nil && rows != nil { // if DB query error rows will be nil, it will return false
ret = true
} else {
ret = false
}
return rows, ret
}
Usage:
var name, age string
rows, is_succeed = execQuery("SELECT `name`, `age` FROM `test` WHERE `id` = ?", "123")
if !is_succeed {
// error
return
}
for rows.Next() { // if have zero result rows, this for route won't execute
err := rows.Scan(&name, &age)
// check if has error & do something
}
If you want to know how much rows returned, just add a counter in for route, use SQL can also achieve this.
sql.Rows likes a list structure, rows *sql.Rows points on first row of returned rows. Use rows.Next() to traverse every rows. I think that's what you've asked.
If you really want to know rows count very often, using a cache mechanic like memcacheDB or Redis or just implement a simple counter yourself can help you solve the problem.