select result in order of maximum match in a string sql - sql

I have a string column Countries in table tblCountry for example 'India, Austrailia, US, UK'.
Now whatever sequence is supplied example 'US, Germany, UK, India, Russia' I have to split the
string on space basis and then display results of all where even a single country is present in the Column Countries value.
Upto this I had achieved by below query. Now the difficult part is I have to display the result first which
has maximum match of column value.
For example if below are the column values:
'India, Austrailia, US, Italy'
'India, Malaysia, Austrailia, US, UK'
'UK, Austrailia, France, Korea, India'
'China, India, US, UK'
and the input string is 'Austrailia, UK, India, Korea, Germany' then the result should be in maximum match comes at top like below:
Output is most matched countries on top by relevance like below for above case
'UK, Austrailia, France, Korea, India'
'India, Malaysia, Austrailia, US, UK'
'India, Austrailia, US, Italy'
'China, India, US, Brazil'
declare #matchCount int = 0;
SET #matchCount = (SELECT count(Item)
FROM dbo.SplitCountry('Austrailia, UK, India, Korea, Germany' , ',')
where Countries like '%'+Item+'%')
SELECT Countries, CASE
WHEN #matchCount >0 THEN #matchCount
ELSE 0
FROM tblCountry
I used a function to split the string 'SplitCountry'. Also I cannot use full text here

You have to
create temp table #t1 (CountriesID, Country)
create temp table #t2 (Country)
populate #t1 by using you split function, so you have:
CountriesID Country
1 India
1 Austrailia
1 US
1 Italy
2 India
2 Malaysia
2 Austrailia
2 US
2 UK
3 ... and so on
populate #t2 by using you split function so t# contains the input values
finally:
SELECT #t1.CountriesID, c.Countries
FROM #t1
INNER JOIN #t2 on #t2.Country = #t1.Country
INNER JOIN tblCountry c ON c.CountriesID = #t1.CountriesID
GROUP BY #t1.ID, c.Countries
ORDER BY COUNT(*) DESC

Finally a lot of research and I got a easy solution for my problem. Below query is perfectly working for me
DECLARE #patterns TABLE (
pattern VARCHAR(20)
);
INSERT INTO #patterns VALUES ('%india%'), ('%france%'), ('%US%'),('%UK%')
;WITH CTEORD AS
(
SELECT a.*,ROW_NUMBER() Over(Partition By country Order By p.pattern) AS RN FROM Countries a
JOIN #patterns p
ON (a.country LIKE p.pattern)
)
select MAX(RN) As RN,country,
from CTEORD group by country
order by RN desc

Related

Union & Pivot multiple tables with different values for similar records

I have multiple tables with the same customer records, but each table has it's own cost currency.
Table 1:
User Country COST_USD
1 USA 10
2 USA 5
3 USA 3
Table 2:
User Country COST_EUR
1 USA 12
2 USA 7
3 USA 5
Table 3:
User Country COST_YEN
1 USA 100
2 USA 50
3 USA 30
What I am looking for is to Union those tables and then pivot the currencies to individual columns (or pivot then union) as follows:
User Country COST_USD COST_EUR COST_YEN
1 USA 10 12 100
2 USA 5 7 50
3 USA 3 3 30
I have tried union all and then pivot but that didn't work since I have differnt currency columns.
Is this what you were thinking of-
select user, country, MAX(COST_USD) COST_USD,MAX(COST_EUR) COST_EUR,MAX(COST_YEN ) COST_YEN
from
(
select user, country, COST_USD, NULL AS COST_EUR, NULL AS COST_YEN from table1
union all
select user, country, NULL AS COST_USD, COST_EUR, NULL AS COST_YEN from table2
union all
select user, country, NULL AS COST_USD, NULL AS COST_EUR, COST_YEN from table3
)T
group by user, country
but if you have many currency columns then you ought to maybe unpivot and union all and the pivot back.
select user, country, currency, amount
from
(select user, country, cost_curr from tableN)U
unpivot
(amount for currency in (COST_EUR, COST_USD,COST_YEN, cost_curr))UPVT
The above is done for all tables and the all resulting unpivots are unioned all and the pivoted back.
As you can see this is quite tedious.
or change you design if possible.
As I mentioned in the comments, this is just a JOIN. Based on your sample data, an INNER JOIN:
SELECT T1.[User], --USER is a reserved keyword, and should not be used for object names
T1.Country,
T1.COST_USD,
T2.COST_EUR,
T3.COST_YEN
FROM dbo.Table1 T1
JOIN dbo.Table2 T2 ON T1.[User] = T2.[User] --USER is a reserved keyword, and should not be used for object names
AND T1.Country = T2.Country
JOIN dbo.Table3 T3 ON T1.[User] = T3.[User] --USER is a reserved keyword, and should not be used for object names
AND T1.Country = T3.Country;
Of course, I doubt all your table have a value for a specific user, so you likely want a FULL OUTER JOIN:
SELECT COALESCE(T1.[User],T2.[User],T3.[User]) AS [User], --USER is a reserved keyword, and should not be used for object names
COALESCE(T1.Country,T2.Country,T3.Country) AS Country,
T1.COST_USD,
T2.COST_EUR,
T3.COST_YEN
FROM dbo.Table1 T1
FULL OUTER JOIN dbo.Table2 T2 ON T1.[User] = T2.[User] --USER is a reserved keyword, and should not be used for object names
AND T1.Country = T2.Country
FULL OUTER JOIN dbo.Table3 T3 ON T3.[User] IN (T1.[User],T2.[User])--USER is a reserved keyword, and should not be used for object names
AND T3.Country IN (T1.Country,T2.Country);
But, like I mentioned, the real solution is fix your design, and have a single table that looks something like this:
CREATE TABLE dbo.YourTable (UserID int,
Country nvarchar(50),
Currency char(3),
Value decimal(12,0));
Then your data would look like this:
INSERT INTO dbo.YourTable
VALUES(1,'USA','USD',10),
(1,'USA','EUR',12),
(1,'USA','YEN',100);
And finally you would get your results with conditional aggregation:
SELECT UserID,
Country,
MAX(CASE Currency WHEN 'USD' THEN Value END) AS COST_USD,
MAX(CASE Currency WHEN 'EUR' THEN Value END) AS COST_EUR,
MAX(CASE Currency WHEN 'YEN' THEN Value END) AS COST_YEN
FROM dbo.YourTable
GROUP BY UserID,
Country;

sql, select only such rows that share a predefined value

I am trying to select such rows that have the same specific value in one of the columns. For example, in the table below there are airlines that fly to different cities. I need to select only such airlines that fly exclusively to the usa. In the table below that would be only the airline2. The city is basically not important for the moment.
airline country_destination city_destination
airline1 usa washington
airline1 eng london
airline1 fra paris
airline2 usa new york
airline2 usa chicago
airline2 usa washington
airline3 can montreal
airline3 usa new york
airline3 can toronto
My first guess returns all the airlines, because in every of them the usa appears at least once.
select distinct airline from table1 where country_destination = 'usa'
I assume I need a nested 'select' and probably a group by airlines? Somewhere directionof what I have below? But I am stuck at this point. Any help is highly appreciated!
select airline, country_destination
from (select airline, country_destination from table1 where country_destination = 'usa' group by airline)
You do need to aggregate.
This is the simplest way I know of to do it:
select airline
from table1
group by airline
having min(country_destination) = max(country_destination)
and min(country_destination) = 'usa';
One method is to check if the airline's row count matches the conditional count (in this case, the amount of rows where the destination is 'usa').
The CTE aggregates the airline data. In the SELECT-statement you can apply the filter to only include airlines where the total row count equals the row count for destination 'usa'. If the counts between count_all and count_usa differ you know there were other country destinations.
with counts as ( select airline,
count(*) as count_all,
sum(case when country_destination == 'usa' then 1 end) as count_usa
from table1
group by 1 )
select airline
from counts
where count_all = count_usa;
you can use below with inner query-
select * from
(select distinct airline, country_destination from table1 ) t
group by airline
having count(airline) = 1 AND country_destination='usa';

Select only values from one column in a table in SQL with condition

Is it possible to get only the countrys who just played in the pre round
Country Round
Germany Pre Round
Germany Quater final
Spain Pre Round
Portugal Pre Round
And I just want to get the countrys which only played in the pre round. So the result should look like this:
Country
Spain
Portugal
You can group by country and set the conditions in the having clause:
select country
from tablename
group by country
having count(*) = 1 and max(round) = 'Pre Round'
You can try the below using not exists
select country from c
where not exists
(select 1 from c as c1 where c.country=c1.country and roundval<>'Pre Round')
Two more for fun. The first is kind of a variation on #forpas', assigning a numeric value to each round, representing the progression through the rounds, and then getting the highest for the country (which would be simpler if the rounds were stored separately with a round number):
select country
from your_table
group by country
having max(case round
when 'Pre Round' then 1
when 'Quater final' then 2
when 'Semi final' then 3
when 'Final' then 4
end) = 1;
If you wanted to find countries that were in the quarters but not semis then you just need to change to = 2, etc.
The second is overkill here, but could be useful to look for more complicated combinations in other types of data:
select country
from your_table
pivot (
count(*) for round in (
'Pre Round' as pre, 'Quater final' as quarter, 'Semi final' as semi, 'Final' as final
)
)
where pre = 1 and quarter = 0 and semi = 0 and final = 0;
Obviously in your example you wouldn't ever have quarter as 0 and then either semi or final as 1 - you can't get to those rounds without playing the quarters; but for other data you might want a mix.
You could use a inner join on subquery for country wih round 're Round' and check for distinct count
select m.Contry
from my_table m
inner join (
select Country
from my_table
where round ='Pre Round'
) t on t.country = m.country
group by m.Country
having count(distinct m.round ) = 1

SQLite query to get table based on values of another table

I am not sure what title has to be here to correctly reflect my question, I can only describe what I want.
There is a table with fields:
id, name, city
There are next rows:
1 John London
2 Mary Paris
3 John Paris
4 Samy London
I want to get a such result:
London Paris
Total 2 2
John 1 1
Mary 0 1
Samy 1 0
So, I need to take all unique values of name and find an appropriate quantity for unique values of another field (city)
Also I want to get a total quantity of each city
Simple way to do it is:
1)Get a list of unique names
SELECT DISTINCT name FROM table
2)Get a list of unique cities
SELECT DISTINCT city FROM table
3)Create a query for every name and city
SELECT COUNT(city) FROM table WHERE name = some_name AND city = some_city
4)Get total:
SELECT COUNT(city) FROM table WHERE name = some_name
(I did't test these queries, so maybe there are some errors here but it's only to show the idea)
As there are 3 names and 2 cities -> 3 * 2 = 6 queries to DB
But for a table with 100 cities and 100 names -> 100 * 100 = 10 000 queries to DB
and it may take a lot of time to do.
Also, names and cities may be changed, so, I can't create a query with predefined names or cities as every day it's new ones, so, instead of London and Paris it may be Moscow, Turin and Berlin. The same thing with names.
How to get such table with one-two queries to original table using sqlite?
(sqlite: I do it for android)
You can get the per-name results with conditional aggregation. As for the total, unfortunately SQLite does not support the with rollup clause, that would generate it automatically.
One workaround is union all and an additional column for ordering:
select name, london, paris
from (
select name, sum(city = 'London') london, sum(city = 'Paris') paris, 1 prio
from mytable
group by name
union all
select 'Total', sum(city = 'London'), sum(city = 'Paris'), 0
from mytable
) t
order by prio, name
Actually the subquery might not be necessary:
select name, sum(city = 'London') london, sum(city = 'Paris') paris, 1 prio
from mytable
group by name
union all
select 'Total', sum(city = 'London'), sum(city = 'Paris'), 0
from mytable
order by prio, name
#GMB gave me the idea of using group by, but as I do it for SQLite on Android, so, the answer looks like:
SELECT name,
COUNT(CASE WHEN city = :london THEN 1 END) as countLondon,
COUNT(CASE WHEN city = :paris THEN 1 END) as countParis
FROM table2 GROUP BY name
where :london and :paris are passed params, and countLondon and countParis are fields of the response class

How to join different columns of same table?

Suppose I have one table with two column, Country and City.
Country
USA
Canada
UK
City
NY
London
I want to join/merge both column records and expect the output like this -
USA
Canada
UK
NY
London
So, what will be the SQL query to merge different columns records of same table?
SELECT Country FROM TABLE
UNION
SELECT City FROM Table
should do it.
Responding to the comment "I am searching for any quick way. Because if I need to merge 10 columns then i have to write 10 Unions! Is there any other way?":
You can use an unpivot, which means you just need to add the column names into a list. Only thing is to watch for data types though. eg:
--CTE for example only
;WITH CTE_Locations as (
select Country = convert(varchar(50),'USA'), City = convert(varchar(50),'NY')
union select Country = 'Canada', City = 'Vancouver'
union select Country = 'UK', City = 'Manchester'
)
--Select a list of values from all columns
select distinct
Place
from
CTE_Locations l
unpivot (Place for PlaceType in ([Country],[City])) u