2

I wrote a query which uses two columns and each of those columns come from different tables. How can I make an index for these columns and is it even possible?

select countryName, balance
from main.country c 
join main.person p on (c.countryId = p.countryId)
where balance = (select MAX(balance) 
                 from main.person p2 
                 join main.country c2 on (c2.countryId = p2.countryId)
                 where c.countryId = c2.countryId 
                   and p.countryId = p2.countryId)
order by countryName;
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
finsters
  • 177
  • 1
  • 2
  • 10
  • Your question seems to be a duplicate of https://stackoverflow.com/questions/8509026/is-cross-table-indexing-possible. – Behrang May 26 '18 at 00:03
  • For some reason sql doesn't allow me to join these tables create index idx_countryperson on main.country c inner join main.person p on c.countryId=p.countryId(c.countryName, p.balance); – finsters May 26 '18 at 00:31
  • 1
    Not _sql_! The product is called _SQL Server_! SQL is a language used by numerous relational database management systems. SQL Server is only on of them. Others include Oracle, MySQL, PostgreSQL, MariaDB, to name a few. – Behrang May 26 '18 at 01:21
  • 1
    Ok, I'll know from now on – finsters May 26 '18 at 01:22

2 Answers2

3

In SQL Server, if you want to create an index on columns from different tables, then you can create a Schema Bound View and build your index on top of that view.

In you case, create a schema bound view:

CREATE VIEW MyBoundView
WITH SCHEMABINDING  
AS  
   -- YOU QUERY 
   select countryName, balance
   from main.country c join main.person p on(c.countryId=p.countryId)
   where balance=(select MAX(balance) from main.person p2 join main.country c2 
   on(c2.countryId=p2.countryId)
   where c.countryId=c2.countryId and p.countryId=p2.countryId)
   order by countryName;  

GO  

Now you can create an index with your two columns on this bound view:

--Example index on the bound view.  
CREATE UNIQUE CLUSTERED INDEX IDX_V1   
   ON MyBoundView (countryName, balance);  
GO  

You may find this article useful.

Hooman Bahreini
  • 14,480
  • 11
  • 70
  • 137
1

This is your query:

select countryName, balance
from main.country c join
     main.person p
     on c.countryId = p.countryId
where balance = (select MAX(balance)
                 from main.person p2 join
                      main.country c2
                      on c2.countryId = p2.countryId
                 where c.countryId = c2.countryId and p.countryId = p2.countryId
                )
order by countryName;

From what I can tell, you want the highest balance in each country, along with duplicates, if any. You can get these using:

select top (1) with ties c.countryName, p.balance
from main.country c join
     main.person p
     on c.countryId = p.countryId
order by rank() over (partition by c.countryId order by p.balance desc);

To get these in order by country name, you need a subquery:

select cp.*
from (select top (1) with ties c.countryName, p.balance
      from main.country c join
           main.person p
           on c.countryId = p.countryId
      order by rank() over (partition by c.countryId order by p.balance desc)
     ) cp
order by countryName;
Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786