MS Access SQL - how do I conditionally set criteria to all? - ms-access

I'm setting up a report that will show me personnel on each shift. I have a form with a combo box where I can select a specific shift, or by leaving it blank show all shifts. Choosing a value from the combo box mirrors that text to a hidden text box which is then passed to the query. Now, getting the report to filter by shift is the easy part, what's kicking me in the teeth right now is how do I set it so that if my Shift Filter box is empty to show all records like it would if the WHERE clause were blank?
Here's my SQL code:
SELECT DISTINCTROW tblPersonnel.EmpID
,tblRank.Rank
,tblPersonnel.NameStr
,tblPersonnel.Shop
,qryShiftRosterSub.Narrative
,qryShiftRosterSubShift.CurrentShift
,qryShiftRosterSubShift.ShopName
,tblRank.ID
FROM (
(
tblPersonnel LEFT JOIN qryShiftRosterSubShift ON tblPersonnel.EmpID = qryShiftRosterSubShift.EmpID
) LEFT JOIN tblRank ON tblPersonnel.Rank = tblRank.ID
)
LEFT JOIN qryShiftRosterSub ON tblPersonnel.EmpID = qryShiftRosterSub.EmpID
WHERE (
((qryShiftRosterSubShift.CurrentShift) = IIf(Len([Forms] ! [frmNavMain] ! [NavigationSubform] ! [ShiftFilter]) = 0, 'Is Not Null', [Forms] ! [frmNavMain] ! [NavigationSubform] ! [ShiftFilter]))
AND ((tblPersonnel.DeleteFlag) = False)
);
I've got a few queries that are chained together and this is the last one before the completed dataset is sent to the report. Like I said, I can get it to show me just a specific shift easily, and by clearing the criteria from CurrentShift I can get it to show all records, but how do I get it to swap between the two based on what's in my filter box?

You can just add an OR clause to check if the combo box is empty. Note that you both need to account for "" empty strings, and Null values. I prefer to check using Nz(MyComboBox) = ""
Implementation:
SELECT DISTINCTROW tblPersonnel.EmpID
,tblRank.Rank
,tblPersonnel.NameStr
,tblPersonnel.Shop
,qryShiftRosterSub.Narrative
,qryShiftRosterSubShift.CurrentShift
,qryShiftRosterSubShift.ShopName
,tblRank.ID
FROM (
(
tblPersonnel LEFT JOIN qryShiftRosterSubShift ON tblPersonnel.EmpID = qryShiftRosterSubShift.EmpID
) LEFT JOIN tblRank ON tblPersonnel.Rank = tblRank.ID
)
LEFT JOIN qryShiftRosterSub ON tblPersonnel.EmpID = qryShiftRosterSub.EmpID
WHERE (
((qryShiftRosterSubShift.CurrentShift) = IIf(Len([Forms] ! [frmNavMain] ! [NavigationSubform] ! [ShiftFilter]) = 0, 'Is Not Null', [Forms] ! [frmNavMain] ! [NavigationSubform] ! [ShiftFilter])
OR Nz([Forms] ! [frmNavMain] ! [NavigationSubform] ! [ShiftFilter]) = "")
AND ((tblPersonnel.DeleteFlag) = False)
);

You can try to use condition like this:
qryShiftRosterSubShift.CurrentShift = [Forms]![frmNavMain]![NavigationSubform]![ShiftFilter]
OR Len(Nz([Forms]![frmNavMain]![NavigationSubform]![ShiftFilter],""))= 0

Why don't you append the 'WHERE' part of the SQL just if your combobox is not empty?

Related

SQL: always return true from `IN` condition

How to make IN condition always return true just like WHERE 1, I tried null but didn't work:
WHERE X IN (NULL)
Is there a way to alway make IN returns true and accept all rows?
return true from something like the following:
where X in ("Any value here to alway return true")
The best you could do is to include the column being compared:
where x in (x)
However, this does not include NULL values. In fact, there is no way you can make this return true:
where NULL in ( . . . )
You could revise this to:
where coalesce(x, '') in (coalesce(x, '')
One way is to use LEFT JOIN :
select t.*
from table t left join
( . . . ) tt
on tt.x = t.x;

How to check for duplicates with an added condition

I'm working with a table of addresses in Power BI. The table also has a column marking some condition, it could be anything so I'll just label it "condition".
I'm trying to create a column (or measure) showing duplicate addresses. The problem I'm having is that both/all duplicates need to meet that other condition. Rows that don't should just be ignored from the start. I thought these nested IF statements would work:
Duplicate =
IF(
CALCULATE(COUNTROWS(Table),
FILTER(Table,Table[Condition]="Yes")),
IF(
CALCULATE(COUNTROWS(Table),
FILTER(Table,Table[Address]=EARLIER(Table[Address])))>1,
"Duplicate",BLANK()
)
)
But duplicate pairs where only one row meets the condition are still marked. What am I doing wrong?
I need all rows elsewhere so I can't filter the query. Also, I know I could add the condition to the concatenation, but that seems sloppy and I assume there's a more "correct" way to do it.
I don't understand how your outer IF function is supposed to work since the first argument is an integer rather than True/False.
Try this instead:
Duplicate =
IF (
COUNTROWS (
FILTER (
Table,
Table[Condition] = "Yes" &&
Table[Address] = EARLIER ( Table[Address] )
)
) > 1,
"Duplicate",
BLANK ()
)
Edit: As you pointed out, this didn't work exactly as intended. Try one of the following instead:
Duplicate =
IF (
COUNTROWS (
FILTER (
Table,
EARLIER ( Table[Condition] ) = "Yes" &&
Table[Condition] = "Yes" &&
Table[Address] = EARLIER ( Table[Address] )
)
) > 1,
"Duplicate",
BLANK ()
)
or
Duplicate =
IF (
Table[Condition] = "Yes" &&
COUNTROWS (
FILTER (
Table,
Table[Condition] = "Yes" &&
Table[Address] = EARLIER ( Table[Address] )
)
) > 1,
"Duplicate",
BLANK ()
)

ZF2 Inner join with where clause returns empty result

When I try the follow mysql query in send I just get back an empty results set (who suposed to be filled).
I tried the follow query in my mysql workbench (gives a results back)
SELECT `websites`.*, `s`.`website_id` AS `websites.id`
FROM `websites`
INNER JOIN `websites_statistics` AS `s` ON `s`.`website_id` = `websites`.`id`
WHERE `websites`.`website` = 'google.com' LIMIT 0,1
And this one in my ZF2 application (empty result set)
$sql = new Sql($this->tableGateway->getAdapter());
$select = $sql->select();
$select->from('websites')
->join(array('s' => 'websites_statistics'), 's.website_id = websites.id', array('websites.id' => 'website_id'), \Zend\Db\Sql\Select::JOIN_INNER)
->where(array('websites.website' => 'google.com'));
$resultSet = $this->tableGateway->selectWith($select);
echo $select->getSqlString();
return $resultSet;
Debug result:
SELECT "websites".*,
"s"."website_id" AS "websites.id"
FROM "websites"
INNER JOIN "websites_statistics" AS "s" ON "s"."website_id" = "websites"."id"
WHERE "websites"."website" = 'google.com'
(!updated) The query a bit so it's more easier. I think there goes something wrong at the first moment because I think "s"."website_id" AS "websites.id" has to flip in the other direction .. "websites.id" AS "s"."website_id" I need websites.id to take record by website_id from the websites_statistics table.
Thanks in advance!
Nick
I got it work. The problem wasn't the query it's self. I had to add the fields of the second table (to one I join) to the model (exchangeArray) of the first table! That did the trick. Thanks you all.

Adding *1 to addAttributeToSort not working

I'm working within a product collection returning products and trying to order them. The problem is one of my product attributes (I find this out at 90% of the way through my project) is a quantity, i.e. 250, 5000 etc. However, I've just found out that despite these being numbers Magento treats them as strings, so therefore the collection returns the following quantities in this example:
50,100,250,500,1000,2000,5000
However, addAttributeToSort('quantity','ASC'); does this:
100,1000,2000,250,50,500,5000
I've done a var_dump() on the collection and ascertained that the values are being treated as strings, hence why this is probably happening. Unfortunately I've got over 6000 products with a lot of custom implementations and configurable products depending on this attribute, so am reluctant to change it. Searching on here I found that adding ORDER BY 'quantity' *1 does actually perform the sort correctly, however I can't seem to implement this clause in the standard addAttributeToSort function.
If anyone could help me implement this, I've tried addAttributeToSort('quantity','*1'); but that doesn't work, just errors.
Many thanks
UPDATE:
Here's the syntax for the query which is generated from the following code:
$collection = $this->getUsedProductCollection($product)
->addAttributeToSelect('*')
->addFieldToFilter('name', array( 'like' => '%' . $stock . '%' ));
$collection->getSelect()->order(new Zend_Db_Expr('quantity' *1));
count($collection);
'SELECT 'e'.*, 'link_table'.'parent_id', IF(at_name.value_id > 0, at_name.value, at_name_default.value) AS 'name', 'price_index'.'price', 'price_index'.'tax_class_id', 'price_index'.'final_price', IF(price_index.tier_price IS NOT NULL, LEAST(price_index.min_price, price_index.tier_price), price_index.min_price) AS 'minimal_price', 'price_index'.'min_price', 'price_index'.'max_price', 'price_index'.'tier_price' FROM 'catalog_product_entity' AS 'e' INNER JOIN 'catalog_product_super_link' AS 'link_table' ON link_table.product_id = e.entity_id INNER JOIN 'catalog_product_website' AS 'product_website' ON product_website.product_id = e.entity_id AND product_website.website_id = '1' INNER JOIN 'catalog_product_entity_varchar' AS 'at_name_default' ON ('at_name_default'.'entity_id' = 'e'.'entity_id') AND ('at_name_default'.'attribute_id' = '65') AND 'at_name_default'.'store_id' = 0 LEFT JOIN 'catalog_product_entity_varchar' AS 'at_name' ON ('at_name'.'entity_id' = 'e'.'entity_id') AND ('at_name'.'attribute_id' = '65') AND ('at_name'.'store_id' = 1) INNER JOIN 'catalog_product_index_price' AS 'price_index' ON price_index.entity_id = e.entity_id AND price_index.website_id = '1' AND price_index.customer_group_id = 0 WHERE (link_table.parent_id = 3781) AND (IF(at_name.value_id > 0, at_name.value, at_name_default.value) LIKE '%PCL Labels%')'
try
$collection->getSelect()->order(new Zend_Db_Expr('quantity' *1));
In the end I achieved this in PHP via ksort(). The database model when implementing any Zend functions was being overridden somewhere and I couldn't afford the time to figure it out.

Why doesn't this SELECT query return the results I expect?

I need help with a select query, but before asking the question, I will give a short description of how my system works:
My database has a many-to-many relationship:
table product:
prd_cod(pk) //stores the product code ex: 0,1,2
cat_cod(fk)
prd_name //stores the product name, ex: tv, gps, notebook
table description_characteristc:
prd_cod(fk)
id_characteristic(fk)
description //stores the description of the characteristic, ex: sony, 1kg, hj10
table characteristic:
id_characteristic (pk)
name_characteristic //store the name of characteristic, ex: brand, weight, model
I have already made a suggest jQuery (in the index.php), where every word I type calls suggest.php, which makes a select and returns the result into the suggestion box in the index:
<?php
header('Content-type: text/html; charset=UTF-8');
$hostname = 'localhost';
$username = 'root';
$password = '';
$dbname = 'cpd';
mysql_connect($hostname, $username, $password)or die('Erro ao tentar conecta o banco
de dados.');
mysql_select_db( $dbname );
if( isset( $_REQUEST['query'] ) && $_REQUEST['query'] != "" )
{
$q = mysql_real_escape_string( $_REQUEST['query'] );
if( isset( $_REQUEST['identifier'] ) && $_REQUEST['identifier'] == "sugestao")
{
$sql = "SELECT p.prd_name, d.description
FROM product p
INNER JOIN description_characteristc d using (prd_cod)
WHERE '".$q."' like concat(p.prd_name, '%') AND
concat(p.prd_name, ' ', d.description) like concat('".$q."', '%')LIMIT 10";
$r = mysql_query( $sql );
if ( $r )
{
echo '<ul>'."\n";
$cont = 0;
while( $l = mysql_fetch_array( $r ) ){
$p = $l['nome'];
$p = preg_replace('/(' . $q . ')/i', '<span style="font-
weight:bold;">$1</span>',
$l['prd_nome'].' '.$l['descricao'].' '.$l['descricao']);
echo "\t".'<li id="autocomplete_'.$cont.'"
rel="'.$l['prd_nome'].'.'.$l['descricao'].'">'. utf8_encode( $p ) .'</li>'."\n";
$cont++;
}
echo '</ul>';
}
}
}
?>
Here are my questions:
Currently when the user types 't', the select brings nothing, only when the user type 'tv' is bringing the result:
tv led
tv plasm
tv samsumg
I would like that when the user type 't' the select bring me 'tv'.
When you type 'tv plasm' it's bringing the same name_characteristic twice:
ex: tv plasm plasm
Currently my select selects the prd_name and the descriptions of table description_characteristc:
tv led
I would like my select could make a inverse select too, ex: led tv.
I would like that when the results of the select were shown, there could be a cache feature that shows the order of the most sought for the less sought; remembering that prd_name stores only 'tv'.
The help I'm looking for can be in the form of select, as in the form of procedure. Also, I can edit the php file.
You should split and join your search query on PHP side like this:
<?php
$words = preg_split("/[^\\w]+/", $q);
$first = $words[0] + "%";
$all = implode(" ", $words) + "%";
?>
then use the variables $first and $all in this query:
SELECT p.prd_name, d.description
FROM product p
JOIN description d
ON d.prd_cod = p.prd_cod
WHERE p.prd_name LIKE '$first'
AND CONCAT(p.prd_name, ' ', d.description) LIKE '$all'
Create an index on product (prd_name) for this to work fast.
If you want the words matched in any order, you will have to create a FULLTEXT index on your tables (this is only possible in MyISAM):
CREATE FULLTEXT INDEX fx_product_name ON product (prd_name)
CREATE FULLTEXT INDEX fx_description_name ON description (description)
and write a query like this:
SELECT p.prd_name, d.description
FROM (
SELECT prd_cod
FROM product pi
WHERE MATCH(prd_name) AGAINST ('lcd tv' IN BOOLEAN MODE)
UNION
SELECT prd_cod
FROM description di
WHERE MATCH(description) AGAINST ('lcd tv' IN BOOLEAN MODE)
) q
JOIN product p
ON p.prd_cod = q.prd_cod
JOIN description d
ON d.prd_cod= p.prd_cod
WHERE MATCH(p.prd_name, d.description) AGAINST ('+lcd +tv' IN BOOLEAN MODE)
Note the search term syntax change: 'lcd tv' in the inner query and '+lcd +tv' in the outer one.
You may also want to set ##ft_min_word_len to 1 for the shorter words like tv or gps to match.
Since MySQL cannot build a fulltext index from two or more tables at once, it would be more simple if you denormalized you tables and put the prd_name into the description table. This way, you could get rid of the joins and just write:
SELECT prd_name, description
FROM description d
WHERE MATCH(prd_name, description) AGAINST ('+lcd +tv' IN BOOLEAN MODE)
You're using the LIKE clause badly and you don't seem to know what "AND" means. It's important to separate "and" as used in casual speech from "AND" as used in programming. AND in programming means "BOTH MUST BE TRUE". "and" in casual speech can mean "one of these conditions, you know what I mean?"
Also, you shouldn't be building SQL like this, it's an accident waiting to happen. You really should find a way to bind variables into SQL statements. I don't know PHP, so I can't help with that.
First, you should be using this in your WHERE clause p.prd_name LIKE '$q%'. Try this outside PHP -- outside the web -- just as a simple SQL query: SELECT * FROM PRODUCT P WHERE P.PRD_NAME LIKE 'T%'.
Second, you should fix "AND" to be "OR", since you want one condition OR the other condition to be true. If you want for BOTH conditions to be true, hardly anything will match.