Equivalent of "IN" that uses AND instead of OR logic? - sql-server

I know I'm breaking some rules here with dynamic SQL but I still need to ask. I've inherited a table that contains a series of tags for each ticket that I need to pull records from.
Simple example... I have an array that contains "'Apples','Oranges','Grapes'" and I am trying to retrieve all records that contain ALL items contained within the array.
My SQL looks like this:
SELECT * FROM table WHERE basket IN ( " + fruitArray + " )
Which of course would be the equivalent of:
SELECT * FROM table WHERE basket = 'Apples' OR basket = 'Oranges' OR basket = 'Grapes'
I'm curious if there is a function that works the same as IN ( array ) except that it uses AND instead of OR so that I can obtain the same results as:
SELECT * FROM table WHERE basket LIKE '%Apples%' AND basket LIKE '%Oranges%' AND basket LIKE '%Grapes%'
I could probably just generate the entire string manually, but would like a more elegant solution if at all possible. Any help would be appreciated.

This is a very common problem in SQL. There are basically two solutions:
Match all rows in your list, group by a column that has a common value on all those rows, and make sure the count of distinct values in the group is the number of elements in your array.
SELECT basket_id FROM baskets
WHERE basket IN ('Apples','Oranges','Grapes')
GROUP BY basket_id
HAVING COUNT(DISTINCT basket) = 3
Do a self-join for each distinct value in your array; only then you can compare values from multiple rows in one WHERE expression.
SELECT b1.basket_id
FROM baskets b1
INNER JOIN baskets b2 USING (basket_id)
INNER JOIN baskets b3 USING (basket_id)
WHERE (b1.basket, b2.basket, b3.basket) = ('Apples','Oranges','Grapes')

There may be something like that in full text search, but in general, I sincerely doubt such an operator would be very useful, outside the conjunction with LIKE.
Consider:
SELECT * FROM table WHERE basket ='Apples' AND basket = 'Oranges'
it would always match zero rows.

If basket is a string, like your example suggests, then the closest you could get would be to use LIKE '%apples%oranges%grapes%', which could be built easily with '%'.implode('%', $tags).'%'
The issue with this is if some of 'tags' might be contained in other tags, e.g. 'supercalifragilisticexpialidocious' LIKE '%super%' will be true.

If you need to do LIKE comparisons, I think you're out of luck. If you are doing exact comparisons invovling matching sets in arbitrary order, you should look into the INTERSECT and EXCEPT options of the SELECT statement. They're a bit confusing, but can be quite powerful. (You'd have to parse your delimited strings into tabular format, but of course you're doing that anyway, aren't you?)

Are the items you're searching for always in the same order within the basket? If yes, a single LIKE should suffice:
SELECT * FROM table WHERE basket LIKE '%Apples%Oranges%Grapes%';
And concatenating your array into a string with % separators should be trivial.

Related

Groupby and count() with alias and 'normal' dataframe: python pandas versus mssql

Coming from a SQL environment, I am learning some things in Python Pandas. I have a question regarding grouping and aggregates.
Say I group a dataset by Age Category and count the different categories. In MSSQL I would write this:
SELECT AgeCategory, COUNT(*) AS Cnt
FROM TableA
GROUP BY AgeCategory
ORDER BY 1
The result set is a 'normal' table with two columns, the second column I named Count.
When I want to do the equivalent in Pandas, the groupby object is different in format. So now I have to reset the index and rename the column in a following line. My code would look like this:
grouped = df.groupby('AgeCategory')['ColA'].count().reset_index()
grouped.columns = ['AgeCategory', 'Count']
grouped
My question is if this can be accomplished in one go. Seems like I am over-doing it, but I lack experience.
Thanks for any advise.
Regards, M.
Use parameter name in DataFrame.reset_index:
grouped = df.groupby('AgeCategory')['ColA'].count().reset_index(name='Count')
Or:
grouped = df.groupby('AgeCategory').size().reset_index(name='Count')
Difference is GroupBy.count exclude missing values, GroupBy.size not.
More information about aggregation in pandas.

Using expressions for a value in Paramaters

I have a report that returns various products depending on which product group you select. Most of these products all have similar product codes that allow me to use the LIKE operator to get the required results. However, for one particular product group, I have the following problem:
VSAMPLES
VSAMPLES2016
VSAMPLES2016DD
VSAMPLESADD
VSAMPLESET
VSAMPLESLARGE
VSAMPLESLARGEADD
VSAMPLESNEW
I only need the top two products to be listed. But using 'VSAMPLES% as a parameter value will return all of these products.
Can i write an expression for the parameter value that will use 'VSAMPLES% and 'VSAMPLES2016% to only return these two products?
EDIT
The query is:
SELECT STRC_CODE, STRC_DESC FROM DeFactoUser.F_ST_Products
WHERE STRC_CODE LIKE #ProductCode
I am using LIKE so I don't have to specify dozens of products for each group.
For one Parameter value I am using 'PA.A% This works perfectly because every product starting with PA.A is needed. In the case of VSAMPLES this isn't the case.
Parameter Values are as follows:
So, can I not add a value to the Aspire tab that will return only those two products?
OK, What i was asking might not have been possible. i fixed the issue by altering my query.
SELECT STRC_CODE, STRC_STATUS, STRC_DESC FROM DeFactoUser.F_ST_Products
WHERE STRC_CODE LIKE #ProductCode AND STRC_CODE NOT IN ('VSAMPLES2016DD',
'VSAMPLESADD', 'VSAMPLESET', 'VSAMPLESLARGE', 'VSAMPLESLARGEADD',
'VSAMPLESNEW')
This results in only the two products I needed being returned when i use VSAMPLES% as a value.
Much simpler then I thought.
Thanks for the input into the question I asked.

Determining Difference Between Items On-Hand and Items Required per Project in Access 2003

I'm usually a PHP programmer, but I'm currently working on a project in MS Access 2003 and I'm a complete VBA newbie. I'm trying to do something that I could easily do in PHP but I have no idea how to do it in Access. The facts are as follows:
Tables and relevant fields:
tblItems: item_id, on_hand
tblProjects: project_id
tblProjectItems: project_id, item_id
Goal: Determine which projects I could potentially do, given the items on-hand.
I need to find a way to compare each project's required items against the items on-hand to determine if there are any items missing. If not, add the project to the list of potential projects. In PHP I would compare an array of on-hand items with an array of project items required, using the array_diff function; if no difference, add project_id to an array of potential projects.
For example, if...
$arrItemsOnHand = 1,3,4,5,6,8,10,11,15
$arrProjects[1] = 1,10
$arrProjects[2] = 8,9,12
$arrProjects[3] = 7,13
$arrProjects[4] = 1,3
$arrProjects[5] = 2,14
$arrProjects[6] = 2,5,8,10,11,15
$arrProjects[7] = 2,4,5,6,8,10,11,15
...the result should be:
$arrPotentialProjects = 1,4
Is there any way to do this in Access?
Consider a single query to reach your goal: "Determine which projects I could potentially do, given the items on-hand."
SELECT
pi.project_id,
Count(pi.item_id) AS NumberOfItems,
Sum(IIf(i.on_hand='yes', 1, 0)) AS NumberOnHand
FROM
tblProjectItems AS pi
INNER JOIN tblItems AS i
ON pi.item_id = i.item_id
GROUP BY pi.project_id
HAVING Count(pi.item_id) = Sum(IIf(i.on_hand='yes', 1, 0));
That query computes the number of required items for each project and the number of those items which are on hand.
When those two numbers don't match, that means at least one of the required items for that project is not on hand.
So the HAVING clause excludes those rows from the query result set, leaving only rows where the two numbers match --- those are the projects for which all required items are on hand.
I realize my description was not great. (Sorry.) I think it should make more sense if you run the query both with and without the HAVING clause ... and then read the description again.
Anyhow, if that query gives you what you need, I don't think you need VBA array handling for this. And if you can use that query as your form's RecordSource or as the RowSource for a list or combo box, you may not need VBA at all.

How to sort a Doctrine DQL Query by the number or members of a relation?

I'm trying to create a query for retrieving objects from a Doctrine database, sorted by the number of members of a specific one-to-many relationship.
More specifically: I have two Entities: Person and Federation. A person can be a member of one federation (Person has 'federation' relationship), and a federation may have n people (Federation as 'people' relationship).
I would like to create a DQL Query that would return the list of Federations, ordered by how many people are members of that Federation. Something along these lines:
SELECT f FROM AcmeStatsBundle:Federation f ORDER BY [number of members of f.people]
That would be the first step. There is an additional second step, which I don't know if is possible to achieve with a single query, which would be filtering the members of the relation prior the counting. Like so:
SELECT f FROM AcmeStatsBundle:Federation f ORDER BY [number of (f.people p where p.attr = value)]
That second one would be the optimal result, but the first one satisfies my needs, if the second case is not feasibly in a single query.
Thanks in advance.
You could do something along the lines of:
public function getFederationsOrderedByNumberOfPeople()
{
return $this->createQueryBuilder('f')
->addSelect('COUNT(p) AS HIDDEN personCount');
->leftJoin('f.people', 'p');
->groupBy('f')
->orderBy('personCount', 'DESC');
}
The HIDDEN keyword was added in Doctrine 2.2, it means that the selected field won't be in the results, and in this case that means you just get your entities back instead of an array.
Reference to DQL SELECT documentation: http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html#dql-select-examples
There are 5 aggregate functions in DQL you can use (Doctrine 2.2): AVG, COUNT, MIN, MAX and SUM.
The following query should work:
SELECT f
FROM AcmeStatsBundle:Federation f
LEFT JOIN f.people p
GROUP BY f.id
ORDER BY COUNT(p)
WHERE p.attr = :some_value
For more DQL trickery I suggest you look up official Doctrine docs.

Query for sorting by name

i have a array of strings i want to write a query such that
first it will count the Id from a particular table say products on the basis of first product names that is in the array
if the value is more than one then select the top one id from the list randomly
otherwise if the count comes one or zero then perform the same query with next value from the string array.
can any body suggest a suitable query for this condition
I assume that the array data are in TMP_ARRAY.
You have two sets products and array, You want to retrieve from products only those entires that are in arrays. For this You should use inner join with proper on clause, next you want to set those results in groups GROUP BY by column name, as you want to operate only on those results that single group size is bigger then one, the clause having needs to be added at the end you want to pick from them 'top' id. And here we have a problem what You mean by 'top'? In data base the data don't have any specific order. I assume that is about the largest, other case in this situation mean only one result, so for both cases we select MAX(ID).
In result I came up with something like this
SELECT MAX(ID) FROM PRODUCTS p INNER JOIN TMP_ARRAY t ON t.NAME = p.NAME GROUP BY p.NAME HAVING COUNT(ID) > 1;
But I'm not sure that i have had understand everything correct.

Resources