DB structure

The second time I try to get an answer to my question: The above is the structure of the database I will describe everything in detail: The first table is the alarm, in which there is only id , firma and model . Everything is clear here. Next comes the costusers table - it stores data on the cost of each alarm in different stores, i.e. The id_sign field stores the id from the signalizacii table, signalizacii field is the field that refers to the uc_id field in the uc1 table, and the cost field is the price. Table uc1 is all shops in all cities.

You just need to select all the alarms from the signalizacii table and add another field in which will store the minimum price for a particular city. If suddenly it happens that in the costusers table costusers not a single price for any kind of alarm in a certain city, then you need to output 0.

Help please, I have been fighting for several days with this query ... SQL is not mine ...

Update

  select signalizacii.*, COALESCE(MIN(CASE WHEN costusers.cost != 0 THEN costusers.cost END), 0) from signalizacii left join costusers on id_sign = id left join uc1 on costusers.id_user = uc1.user_id where uc1.city = 'Краснодар' group by signalizacii.id 

That's what I wanted - it seemed to me. But it was not here that if the price for any alarm is not set in the costusers table, then this alarm is not displayed at all.

The problem is still not solved. Please help ... Please. The above result, which I cited, unfortunately does not display an alarm at all if the price for it is not set by any of the stores in the specified city. And it should be displayed but the price should be 0. Help please.

  • What does it mean "in a particular city", it was originally set in the request ie we choose prices only for a particular city. Or it is necessary to show in separate lines the product-city-price_v_city for all cities in the system? - Mike
  • one
    Try select signalizacii.*, min(cost), city from signalizacii left join costusers on id_sign = id left join uc1 on uc_id = costusers.id_user group by signalizacii.id, signalizacii.firma, signalizacii.model, city - nick_n_a
  • one
    @nick_n_a If the city is set, and the condition "show all products, even without prices" is preserved, then the city condition must be placed in on for uc1 - Mike
  • 2
    @nick_n_a, since the author, apparently, is too lazy, will do it for him: sqlfiddle.com/#!9/db733/1/0 . Your request is immediately there. I think, it is necessary to add still check on null . - Pyramidhead
  • one
    Possible duplicate question: SQL query is complicated - Dmitry Nail

6 answers 6

As I understand it, you need to choose the minimum prices for all products in all stores, even if they are not specified. Alternatively, you can use such a query based on what the distinguished nick_n_a has suggested :

 SELECT signalizacii.*, name, coalesce(MIN(cost), 0) FROM uc1 JOIN signalizacii LEFT JOIN costusers ON costusers.id_user = uc_id AND costusers.id_sign = id GROUP BY name, model 

Working example: http://sqlfiddle.com/#!9/c9294/1/0

With the selection of the city:

 SELECT signalizacii.*, name, coalesce(MIN(cost), 0) FROM uc1 JOIN signalizacii LEFT JOIN costusers ON costusers.id_user = uc_id AND costusers.id_sign = id WHERE city='Краснодар' GROUP BY name, model 
  • Almost what you need, but you need to select the alarm for a particular city, for example, Moscow, that is, the city is set in the query itself ... - Alexander
  • WHERE uc_id = 'id нужного города' , so add a simple WHERE uc_id = 'id нужного города' before the GROUP BY . - Pyramidhead
  • Che is wrong ... everywhere zeros displays although this is not so .... (((((( - Alexander
  • select signalizacii. *, coalesce (min (costusers.cost), 0) from signalizacii left join costusers on id_sign = id left join uc1 on uc_id = costusers.id_user and costusers.id_user = uc1.user_id where uc1.city = 'Krasnodar' group by signalizacii.id - Alexander
  • I can not find the error .... empty result (((( - Alexander

Are you trying to kill two birds with one stone? Why is it so necessary to do everything with a single SQL query? What will you achieve with this?

Surely the list of alarms you have more or less fixed, that is, does not change every second. So you can download a list of all alarms with a single request, save this list in the cache in the desired order. Then, as necessary, request prices for a particular city, while visualizing, substituting prices for each alarm into the column.

Think about it this way: it’s not so important to do everything in one request, as it is important that you yourself can understand what is happening here in a year or two, when you need to fix a bug very urgently. In one case, you immediately immediately figure out what was happening, spending 10 minutes to fix. In another case, you will spend an hour or two to restore the train of thought and remember all the hacks used to write the request.

    There are a lot of LEFT JOINs, it would be better to do zero prices with a separate UNION, and otherwise it works as requested.

     SELECT DISTINCT s.*, ISNULL(m.mincost, 0) AS 'mincost' FROM #signal_signalizacii s LEFT JOIN #signal_costusers u ON u.id_sign = s.id LEFT JOIN #signal_uc1 c ON u.[user_id] = c.uc_id AND c.city = 'Краснодар' OUTER APPLY ( SELECT MIN(cost) AS 'mincost' FROM #signal_costusers WHERE id_sign = s.id AND [user_id] = c.uc_id AND c.uc_id IS NOT NULL ) m 

      Can you clarify all the same in which database the query is executed? this is mysql oracle postgre or mssql

      If it were Oracle, one could use analytical functions: http://www.sql.ru/blogs/oracleandsql/1926 , construct

       MIN(cost) OVER(Partition BY city) 

      works exactly as you need. If you specify the database, you can search for an implementation similar to analytical functions in Oracle

      Sorry I did not notice that this is Mysql, then please check: http://sqlfiddle.com/#!9/0de13/11

      deal with the zeros themselves then what to replace them:

       /* все сигнализации из таблицы signalizacii */ SELECT s.* FROM signalizacii s ; /* и добавить минимальную цену по городу, т.е. добавляем поле Город min_cost_s_c - минимальная цена на сигнализацию по городу */ SELECT s.*, u.city, min(c.cost) as min_cost_s_c FROM signalizacii s left join costusers c ON s.id = c.id_sign left join uc1 u ON c.id_user = u.user_id group by s.id, s.firma, s.model, u.city; /* если нужна минимальная цена по городу не зависимо от сигнализации, просто минимальная цена то делаем так */ SELECT s.*, t.city, t.cost FROM signalizacii s left join ( select u.city, min(c.cost) as cost, max(c.id_sign) as id_sign from costusers c left join uc1 u ON c.id_user = u.user_id GROUP BY u.city) t ON s.id = t.id_sign; 

      or if max confuses (c.id_sign), then you can try differently

       /* если нужна минимальная цена по городу не зависимо от сигнализации, просто минимальная цена то делаем так */ SELECT s.*, t.city, t.cost FROM signalizacii s left join ( select u.city, min(c.cost) as cost, group_concat(c.id_sign) as id_sign from costusers c left join uc1 u ON c.id_user = u.user_id GROUP BY u.city) t ON s.id IN (t.id_sign); 
      • The question has a MySQL tag. So this is hardly an Oracle ... - Akina
      • for sure. then please check sqlfiddle.com/#!9/0de13/11 - Ravshan Abdulaev
      • @Akina originally had no mysql tag. I added it, taking information from the commentary in question - Bald
        left join uc1 on costusers.id_user = uc1.user_id where uc1.city = 'Краснодар' 

      This is such a way to invisibly write an inner join , possibly simultaneously confusing and query optimizer. Left join in case the string is not found uses for all fields NULL . NULL can not be equal to anything, even to itself. Therefore, a comparison with a constant string does not give true and the whole string is discarded. What turns a query into an inner join .

      You must either consider the possibility of NULL appearing explicitly.

        left join uc1 on costusers.id_user = uc1.user_id where (uc1.city is null or uc1.city = 'Краснодар') 

      Or, which is usually clearer, move the search condition to the join condition:

        left join uc1 on costusers.id_user = uc1.user_id and uc1.city = 'Краснодар' -- where при этом уже не нужен 

      Eventually

      Getting all the rows from the table with the strange name signalizacii and adding the minimum value proposition in the selected city

        select signalizacii.*, COALESCE(MIN(CASE WHEN costusers.cost != 0 THEN costusers.cost END), 0) from signalizacii left join costusers on id_sign = id left join uc1 on costusers.id_user = uc1.user_id and uc1.city = 'Краснодар' group by signalizacii.id 

      Or you can rewrite the query like this:

       select signalizacii.*, COALESCE(mincost, 0) from signalizacii left join ( select id_sign, min(costusers.cost) as mincost from costusers join uc1 using(id_user) where uc1.city = 'Краснодар' and costusers.cost > 0 -- исходно у вас != 0, наверное логичнее > 0? group by id_sign ) m ON id = id_sign 

        Use on health)

         select s.*, IF(costs.minCost is null, 0, costs.minCost) as minCost FROM signalizacii s LEFT JOIN (select min(cost) as minCost, c.id_sign FROM costusers c LEFT JOIN uc1 ON c.id_user = uc1.uc_id WHERE city = "BAKU" GROUP BY c.id_sign) costs ON s.id = costs.id_sign