my sql query with possible combinations - mysql

i have the search requirement that with doing search option for rental house.
city,price range,numberOfRooms are the criteria.
if the user does not mention any of the details and click submit we have to show all the results.
if the user mentioned for example price range is 5000 to 10000 then it has to give the results for considering all cities,all possible 1bhk,2bhk,3bhk...
how to write single query that covers all the possibilities
i have this idea in my mind..
let us consider only city and price are the option and no other options are there for the better explanation.
i create a table called city
city
option cityname
1 delhi
2 hyderabad
3 bangalore
4 delhi
4 hyderabad
4 bangalore
SELECT *
FROM rental
WHERE city IN (select cityname from city where option=#{option_value}) and price>=#{minPrice} and price<=#{maxPrice};
Do we need to create the table city?
Is there any to send the values in list and based on option those list values should come.
is it correct?

Here is another way to do this, by using optional parameters something like:
SELECT *
FROM rental
WHERE 1 = 1
AND (#city IS NULL OR city = #city)
AND (#PricerangeFlag IS NULL OR price BETWEEN #minPrice AND #maxPrice)
..
If any of the parameters #city, #pricerangeFlag or any other parameter passed this way to this query, passed with a NULL value then the whole predicate, for example, AND (#city IS NULL OR city = #city) will be evaluated to true without getting into the second predicate OR city = #city since #city is NULL evaluates to true. The same with other parameters and if all the parameters passed with the value NULL to the query the WHERE clause wil be evaluated to WHERE 1 = 1 which is always true predicate, there for act like it wasn't presented and returns all rows.
Note that in case of the price ranges parameters I used a flag parameter to disable the two parameters #minPrice and #maxPrice

Related

SSRS Row Group with non-aggregated measure column

I'm not finding any other questions exactly like mine, so it's time to ask.
I have an SSRS 2016 report. It's got a regional hierarchy (State, City, Location). And it's got one measure column that is a calculation performed in the stored procedure. Due to the nature of the calculation, the value of the calculation for a city must be performed independently in the stored procedure. It's not a simple aggregation of the Locations in the City, so it cannot simply be aggregated in the report. I need the report to expand and contract on the regional hierarchy columns, and to pull the measure values straight from the dataset with aggregating.
In other words
I have a dataset like this:
State City Location Measure
FL NULL NULL 25
FL Miami NULL 12
FL Miami Walmart 52
FL Miami Kmart 3
FL Orlando NULL 33
FL Orlando Sears 4
I need for the report to have collapsible rowgroups at the State and City levels, with Location being the "detail" level row group. But I need the value of Measure to be 12 for Miami, and not some aggregation of 2 & 3 (Walmart and Kmart).
I figure the approach must be either:
Use traditional row groups and do some kind of programming in the expression of the measure column for the two upper-level row groups, or
Don't put row groups on the tablix and do conditional formatting of the rows and some kind of programming in the toggle properties.
But in both cases, I'm not seeing anything I can do that SSRS will actually allow for the "some kind of programming" bit.
Is there a solution?
If you must do it in the report, I think you could use a table a FILTER out the NULL city and location values. When you need them you could do a Lookup to get the value from the dataset. This will lookup the Measure value for a City where the IIF will act as a filter for the NULL value - if there is a location the City will have an X0 added and won't match the Lookup City.
=Lookup(Fields!City.Value, Fields!City.Value & IIF(ISNOTHINGFields!Location.Value), "", "x0"), Fields!Measure.Value, "Dataset1")
If you can put your current results in a temp table, a better way would be to add the totals as seperate fields in the query.
SELECT 'FL' AS State, NULL AS City , NULL as Location, 25 as Measure
INTO #TABLE
UNION
SELECT 'FL' AS State, 'Miami' AS City , NULL AS Location, 12 as Measure
UNION
SELECT 'FL' AS State, 'Miami' AS City , 'Walmart' as Location, 52 as Measure
UNION
SELECT 'FL' AS State, 'Miami' AS City , 'Kmart' as Location, 3 as Measure
UNION
SELECT 'FL' AS State, 'Orlando' AS City , null as Location, 33 as Measure
UNION
SELECT 'FL' AS State, 'Orlando' AS City , 'Sears' as Location, 4 as Measure
--DROP TABLE #TABLE
SELECT T.*, T_S.Measure AS STATE_MEASURE, T_C.Measure AS CITY_MEASURE
FROM #TABLE T
LEFT JOIN #TABLE T_S ON T.State = T_S.State AND T_S.City IS NULL
LEFT JOIN #TABLE T_C ON T.State = T_C.State AND T_C.City = T.City AND T_C.Location IS NULL
WHERE T.City IS NOT NULL AND T.Location IS NOT NULL
This will let you just have the recordsd you need with the additional comlumns for the summary data.
Group on state and city and don't use SUM() for your Measure column
Your layout could be like the one below

MySQL - counter query

Have two tables users and user_demographics
users has the basic structure of (does have more fields but not needed here):
id name email gender age ethnicity
1 test1 test1#test.com 1 1 1
2 test2 test2#test.com 1 2 1
3 test3 test3#test.com 2 3 2
4 test4 test4#test.com 3 1 1
5 test5 test5#test.com 2 4 5
**Gender**:
1 - Male,
2 - Female,
3 - Prefer not to say
**Age**:
1 - 16-20,
2 - 21-24,
3 - 25-30,
4 - 31-24
**Ethnicity**:
1 - White,
2 - Black,
5 - Prefer not to say
and so on and currently have around 1000 users.
user_demographics structure is:
coreid, type, option (for the sake of this question 'type' will be text, just to make it clearer)
coreid, type option
1 gender 1
1 gender 2
1 age 1
1 age 3
1 ethnicity 1
2 gender 2
2 gender 3
2 age 3
3 gender 1
On a web based form I have 3 sets of checkbox lists, one for each option gender, age, ethnicity and the a user can select multiple from each. They click update and these details are stored in the mysql database as above. coreid is related to another table, but not relevant here.
What I'm trying to do is get a total count of users for each coreid regardless of what type it is. The count should get smaller the more options you select. So coreid 3 should have the biggest count because I've only selected one option.
Example: coreid 3 is selecting all males
Example: coreid 2 is selecting all (females AND 'prefer not to say') AND age range 25-30
Struggling on how to create a single query that will give me the results I need, hope this makes sense.
The idea behind the over all system is that we have a large form that a user fill outs and we store in the information in the users table. Then a member of the admin team can go in and select these users by selecting options from the various demographics information we have collected. So they might just want to see everyone that has ticked the gender options of 'male' and 'prefer not to say' for example. Another admin member may go in and say they want all males, between the age of 25-30. Or they could just tick all options under gender. The idea is that they can select any combination and get a list of results. At the minute I just need to get a count back for the combination selected.
By the SOUNDS of it, you are probably going to need to do with dynamic SQL where you actually build the query on-the-fly, then execute that. Also, to clarify what I THINK you are asking is as follows. CoreID is like a set of filters that some manager is interested in getting count and or details of specific users. They are interested in
EITHER gender condition (1 or 2)
AND EITHER age condition (1 or 3)
AND just the one ethnicity
to possibly target products that might hit those demographics. So you would pre-query every record for CoreID = 1 then start building your query. You would want to order your query by the TYPE to group common items such as the gender, age, ethnicity categories.
Then, within your either localized code (not indicated such as C#, VB, java, whatever), you would need to build the query in such a way that you parenthesis OR those within same category, and logical AND between different such as
where
( Gender = 1
OR Gender = 2 )
AND ( Age = 1
OR Age = 3 )
AND ( Ethnicity = 1 )
If you are trying to write as a MySQL stored procedure, it would be a type of dynamic SQL query... either way, the WHERE clause needs to be constructed from the Core criteria someone is looking for.
You are correct, the last one would be easiest for CoreID = 3 would be a simple
WHERE ( Gender = 1 )
Clarify language source and I or others might be able to offer additional direction, but if I am accurate, you should try to write your own first pass of code, but I will shoot out a pseudo-code for you something like
Get Records Ordered for one CoreID, order by the type of criteria.
prep variable identifying if pending open Parenthesis
prep variable identifying last "type" building for.
for each record
If new type
if has Open Parenthesis
add closing paren
add logical AND before the next entry we are getting
add open parenthesis
set flag we have open parenthesis
else
since same type as last type, add logical OR
go to next record, repeat.
If after last record we would always need to close parenthesis even if a single criteria

How To Populate One Column Based On Another Columns Data In Same Table?

I have two sets of data I joined into a single table. One was USA addresses and the other was Canadian addresses. I need the option to be able to sort by Country. So I inserted a blank country column into my table and my table now looks like this:
state | country | zip
-----------------------
| |
| |
I have the state and zip data but my country column is empty. Since US zip code format is 5 digits (ex. 12345) and CAN zip are formatted like (ex. G5Y 5S7) is it possible with mysql to populate the country data with some sort of...
UPDATE table
SET country = US
WHERE zip (LIKE or =) (US zip format);
And then go back and use some sort of WHERE zip LIKE NULL to populate the rest of country data with CAN?
Thanks
You could check the length of the value in the zip column.
UPDATE table
set country = 'US'
where char_length(zip) = 5;
then:
UPDATE table
set country = 'CAN'
where country is null
-- or, in one go --
UPDATE table t
set country =
(case when char_length(t.zip) = 5
then 'US'
else 'CAN'
end);

Querying normalized database, 3 tables

I have three tables in a MySQL database:
stores (PK stores_id)
states (PK states_id)
join_stores_states (PK join_id, FK stores_id, FK states_id)
The "stores" table has a single row for every business. The join_stores_states table links an individual business to each state it's in. So, some businesses have stores in 3 states, so they 3 rows in join_stores_states, and others have stores in 1 state, so they have just 1 row in join_stores_states.
I'm trying to figure out how to write a query that will list each business in one row, but still show all the states it's in.
Here's what I have so far, which is obviously giving me every row out of join_stores_states:
SELECT states.*, stores.*, join_stores_states.*
FROM join_stores_states
JOIN stores
ON join_stores_states.stores_id=stores.stores_id
JOIN states
ON join_stores_states.states_id=states.states_id
Loosely, this is what it's giving me:
store 1 | alabama
store 1 | florida
store 1 | kansas
store 2 | montana
store 3 | georgia
store 3 | vermont
This is more of what I want to see:
store 1 | alabama, florida, kansas
store 2 | montana
store 3 | georgia, vermont
Suggestions as to which query methods to try would be just as appreciated as a working query.
If you need the list of states as a string, you can use MySQL's GROUP_CONCAT function (or equivalent, if you are using another SQL dialect), as in the example below. If you want to do any kind of further processing of the states separately, I would prefer you run the query as you did, and then collect the resultset into a more complex structure (hashtable of arrays, as a simplest measure, but more complex OO designs are certainly possible) in the client by iterating over the resulting rows.
SELECT stores.name,
GROUP_CONCAT(states.name ORDER BY states.name ASC SEPARATOR ', ') AS state_names
FROM join_stores_states
JOIN stores
ON join_stores_states.stores_id=stores.stores_id
JOIN states
ON join_stores_states.states_id=states.states_id
GROUP BY stores.name
Also, even if you only need the concatenated string and not a data structure, some databases might not have an aggregate concatenation function, in which case you will have to do the client processing anyway. In pseudocode, since you did not specify a language either:
perform query
stores = empty hash
for each row from query results:
get the store object from the hash by name
if the name isn't in the hash:
put an empty store object into the hash under the name
add the state name to the store object's stores array

How to prioritize a LIKE query select based on string position in field?

I am attempting to query a table for a limited resultset in order to populate an autocomplete field in javascript. I am, therefore, using a LIKE operator with the partial string entered.
If I have, for example, a table such as:
tblPlaces
id country
1 Balanca
2 Cameroon
3 Canada
4 Cape Verde
5 Denmark
For the sake of this example, let's say I want two rows returning - and yeah, for this example, I made up a country there ;) I want to prioritize any instance where a partial string is matched at the beginning of country. The query I began using, therefore is:
SELECT id, country FROM tblPlaces WHERE country LIKE 'ca%' LIMIT 2
This returned 'Cameroon' and 'Canada' as expected. However, in instances where there are no two names in which the string is matched at the beginning of a word (such as 'de'), I want it to look elsewhere in the word. So I revised the query to become
SELECT id, country FROM tblPlaces WHERE country LIKE '%ca%' LIMIT 2
This then returned 'Cape Verde' and 'Denmark', but in doing so broke my original search for 'ca', which now returns 'Balanca' and 'Cameroon'.
So, my question is, how to go about this using a single query that will prioritize a match at the start of a word (perhaps I need to use REGEXP?) I am assuming also that if the 'country' column is indexed, these matches will at least be returned with subsequent alphabetical priority (i.e. Cameroon before Canada etc).
If you mean to prioritize matches that are Exactly at the start...
SELECT id, country
FROM tblPlaces
WHERE country LIKE '%ca%'
ORDER BY CASE WHEN country LIKE 'ca%' THEN 0 ELSE 1 END, country
LIMIT 2
EDIT
More generic and possibly faster (Assuming "closer to the start the 'better' the match")...
SELECT id, country
FROM tblPlaces
WHERE country LIKE '%ca%'
ORDER BY INSTR(country, 'ca'), country
LIMIT 2