Question

I am creating a stored procedure to search user's Towns. From the User Interface user will select multiple towns that will be sent to the stored procedure. Sample input of the towns parameter for the stored procedure would be like orangi,faisal,nazimabad.

Towns that are stored in the table are

  • Orangi
  • Korangi
  • Shah Faisal
  • Shahrah-e-Faisal
  • Nazimabad
  • North Nazimabad

Now I want to select all those above records against that input. That is I want to use LIKE operator with IN from a stored procedure's parameter.

I don't know how many towns would be there in the input. it could be just one, or two or three or all these mentioned above.

I want to search all the towns against that query

Sample Stored Procedure is

CREATE PROCEDURE `GetUsersByTown`(
IN `SearchTowns` VARCHAR(200) -- `ORANGI,FAISAL,NAZIMABAD`
)
BEGIN
      SELECT
      name,
      Town,
      FROM userLocation where Town in (SearchTowns)
END

Expected Outcome

  • Name --- Town
  • Hamza --- Orangi
  • Jamal --- Korangi
  • Hasham --- Shah Faisal
  • Aliyan --- Shahrah-e-Faisal
  • Danish --- Nazimabad
  • Farrukh --- North Nazimabad

I have tried to use find_in_set() but FIND_IN_SET does not accept wildcards like % and it doesn't use index?

I have also looked at using REGEXP ValueA|ValueB but I don't know how to put the input parameter that is comma separated values in that REGEXP

Was it helpful?

Solution

  • Use REPLACE(SearchTowns, ',', '|') to change commas to pipes.
  • Put that result in, say, @regexp.
  • Construct, via CONCAT a single SELECT with

    SET @sql = CONCAT('SELECT
      name,
      Town,
      FROM userLocation where Town REGEXP "', @regexp, '"');
    
  • PREPARE and EXECUTE the query.

That query should look like:

SELECT
      name,
      Town,
      FROM userLocation where Town REGEXP "orangi|faisal|nazimabad"

(You could manually run that to verify that the correct rows are delivered.)

Also, be sure to have case-folding COLLATION, such as utf8mb4_unicode_520_ci for Town. (That is indicated by the trailing _ci.)

Code

DELIMITER //
CREATE PROCEDURE `GetUsersByTown`(
    IN `SearchTowns` VARCHAR(200) -- `ORANGI,FAISAL,NAZIMABAD`
)
BEGIN
IF (SearchTowns IS NULL) THEN
    SELECT name, Town
        FROM userLocation;
ELSE
    SET @towns = REPLACE(SearchTowns, ',', '|');
    SELECT name, Town
        FROM userLocation
        WHERE Town REGEXP (@towns);
END IF;
END //
DELIMITER ;

OTHER TIPS

CREATE PROCEDURE GetUsersByTown( IN SearchTowns LONGTEXT ) BEGIN SELECT name, Town, FROM userLocation where FIND_IN_SET(Town,(SearchTowns))>0 END

This is a stored procedure which splits inputed comma-separated string (SearchTowns) into separate rows, inserts these rows into temporary table (Towns) and then uses join between userLocation and Towns tables on required conditions (where userLocation.town is like %town% from Towns table). All other rows which don't correspond this condition will be eliminated from the final resultset.
Also I used DISTINCT to avoid rows duplication in case if userLocation.town corresponds to more than one row from Towns table. For example, if SearchTowns contains 'Orangi' and 'Korangi' then users who are located in Korangi will be joined with both towns (because 'korangi' like '%orangi%').

CREATE PROCEDURE GetUsersByTown(SearchTowns VARCHAR(200))

    BEGIN
      DECLARE pos INT Default 0 ;
      DECLARE str VARCHAR(200);
      CREATE TEMPORARY TABLE Towns(town VARCHAR(200));
      #Loop through comma-separated values
      #pos - is the number of current word within search string
      simple_loop: LOOP
         SET pos=pos+1;
         SET str=REPLACE(SUBSTRING(SUBSTRING_INDEX(SearchTowns, ',', pos),
                    LENGTH(SUBSTRING_INDEX(SearchTowns, ',', pos -1)) + 1),
                    ',', '');
         IF str='' THEN
            LEAVE simple_loop;
         END IF;
         #Do Inserts into temp table here with str going into the row
         insert into Towns values (str);
    END LOOP simple_loop;
    SELECT DISTINCT
      u.name,
      u.Town
    FROM userLocation AS u
    JOIN Towns AS t ON u.Town LIKE CONCAT('%', t.town, '%');
   DROP TEMPORARY TABLE Towns;
END
Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top