mysql_real_escape_string / Говнокод #12551 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99
  100. 100
ALTER PROCEDURE [dbo].[prodam_Получить_Начисления_По_ЛС]
	@кодЛС uniqueidentifier,
	@дата date,
	@источникНачислений nvarchar(50)
AS
BEGIN
	SET NOCOUNT ON;
	IF @источникНачислений = 'AccountCharge_Lain'
	BEGIN
		SELECT 
		   CAST(MONTH(@дата) as nvarchar(2))+'.'+CAST(YEAR(@дата) as nvarchar(4)) as 'Расчетный период'
		  ,ach.ID as 'Начисление'
		  ,suc.Title as 'Услуга'
		  ,ach.[Formula] as 'Формула'
		  ,ach.[FormulaWithValues] as 'Формула со значениями'
		  ,CAST(ach.[SumOfPaymentEnteredTheLastMonth] as decimal(19,2)) as 'Оплаты поступившие в предыдущем месяце (руб.)'
		  ,CAST(ach.[SumOfRecalculationForTheLastMonth]as decimal(19,2)) as 'Перерасчет за предыдущий период (руб.)'
		  ,CAST(ach.[SumOfDebtOrOverpayment]as decimal(19,2)) as 'Долг (+), переплата (-) (руб.)'
		  ,um.Title as 'Единица измерения (по нормативу / приборам учета)'
		  ,CAST(ach.[SumOfTariffForUnitOfService]as decimal(19,2)) as 'Тариф за единицу услуги (руб.)'
		  ,CAST(ach.[SumOfChargeForMonthUnderTheTariff]as decimal(19,2)) as 'Начислено за месяц по тарифу (руб.)'
		  ,CAST(ach.[SumOfShortShipmentOfService]as decimal(19,2)) as 'Сумма недопоставки (руб.)'
		  ,CAST(ach.[SumOfPaymentInViewOfShortShipment]as decimal(19,2)) as 'Начислено к оплате с учетом недопоставки (руб.)'
		  ,CAST(ach.[AmountOfDaysOfShortShipmentOfService]as decimal(19,2)) as 'Недопоставка услуг (дней)'
		  ,suc.ID as 'ID'
		FROM 
		  [RegionDBNew].[dbo].Account acc
		  INNER JOIN [RegionDBNew].[dbo].[AccountCharge_Lain] ach ON 
			ach.CalculationYear = YEAR(@дата) AND 
			ach.CalculationMonth = MONTH(@дата) AND
			ach.AccountID = acc.ID
		  LEFT JOIN [RegionDBNew].[dbo].UnitOfMeasure um ON ach.[UnitOfMeasureID] = um.ID
		  LEFT JOIN [RegionDBNew].[dbo].[ServiceUnderAccount] suc ON suc.ID = ach.ServiceUnderAccountID
		WHERE
		  acc.ID = @кодЛС
		ORDER BY 
		  suc.Title;
	END
	ELSE IF @источникНачислений = 'AccountCharge_Prodam'
	BEGIN
		SELECT 
		   CAST(MONTH(@дата) as nvarchar(2))+'.'+CAST(YEAR(@дата) as nvarchar(4)) as 'Расчетный период'
		  ,ach.ID as 'Начисление'
		  ,suc.Title as 'Услуга'
		  ,ach.[Formula] as 'Формула'
		  ,ach.[FormulaWithValues] as 'Формула со значениями'
		  ,CAST(ach.[SumOfPaymentEnteredTheLastMonth] as decimal(19,2)) as 'Оплаты поступившие в предыдущем месяце (руб.)'
		  ,CAST(ach.[SumOfRecalculationForTheLastMonth] as decimal(19,2)) as 'Перерасчет за предыдущий период (руб.)'
		  ,CAST(ach.[SumOfDebtOrOverpayment] as decimal(19,2)) as 'Долг (+), переплата (-) (руб.)'
		  ,um.Title as 'Единица измерения (по нормативу / приборам учета)'
		  ,CAST(ach.[SumOfTariffForUnitOfService] as decimal(19,2)) as 'Тариф за единицу услуги (руб.)'
		  ,CAST(ach.[SumOfChargeForMonthUnderTheTariff] as decimal(19,2)) as 'Начислено за месяц по тарифу (руб.)'
		  ,CAST(ach.[SumOfShortShipmentOfService] as decimal(19,2)) as 'Сумма недопоставки (руб.)'
		  ,CAST(ach.[SumOfPaymentInViewOfShortShipment] as decimal(19,2)) as 'Начислено к оплате с учетом недопоставки (руб.)'
		  ,CAST(ach.[AmountOfDaysOfShortShipmentOfService] as decimal(19,2)) as 'Недопоставка услуг (дней)'
		  ,suc.ID as 'ID'
		FROM 
		  [RegionDBNew].[dbo].Account acc
		  INNER JOIN [RegionDBNew].[dbo].[AccountCharge_Prodam] ach ON 
			ach.CalculationYear = YEAR(@дата) AND 
			ach.CalculationMonth = MONTH(@дата) AND
			ach.AccountID = acc.ID
		  LEFT JOIN [RegionDBNew].[dbo].UnitOfMeasure um ON ach.[UnitOfMeasureID] = um.ID
		  LEFT JOIN [RegionDBNew].[dbo].[ServiceUnderAccount] suc ON suc.ID = ach.ServiceUnderAccountID
		WHERE
		  acc.ID = @кодЛС
		ORDER BY 
		  suc.Title;
	END
	ELSE IF @источникНачислений = 'AccountCharge'
	BEGIN
		SELECT 
		   CAST(MONTH(@дата) as nvarchar(2))+'.'+CAST(YEAR(@дата) as nvarchar(4)) as 'Расчетный период'
		  ,ach.ID as 'Начисление'
		  ,suc.Title as 'Услуга'
		  ,ach.[Formula] as 'Формула'
		  ,ach.[FormulaWithValues] as 'Формула со значениями'
		  ,CAST(ach.[SumOfPaymentEnteredTheLastMonth] as decimal(19,2)) as 'Оплаты поступившие в предыдущем месяце (руб.)'
		  ,CAST(ach.[SumOfRecalculationForTheLastMonth] as decimal(19,2)) as 'Перерасчет за предыдущий период (руб.)'
		  ,CAST(ach.[SumOfDebtOrOverpayment] as decimal(19,2)) as 'Долг (+), переплата (-) (руб.)'
		  ,um.Title as 'Единица измерения (по нормативу / приборам учета)'
		  ,CAST(ach.[SumOfTariffForUnitOfService] as decimal(19,2)) as 'Тариф за единицу услуги (руб.)'
		  ,CAST(ach.[SumOfChargeForMonthUnderTheTariff] as decimal(19,2)) as 'Начислено за месяц по тарифу (руб.)'
		  ,CAST(ach.[SumOfShortShipmentOfService] as decimal(19,2)) as 'Сумма недопоставки (руб.)'
		  ,CAST(ach.[SumOfPaymentInViewOfShortShipment] as decimal(19,2)) as 'Начислено к оплате с учетом недопоставки (руб.)'
		  ,CAST(ach.[AmountOfDaysOfShortShipmentOfService] as decimal(19,2)) as 'Недопоставка услуг (дней)'
		  ,suc.ID as 'ID'
		FROM 
		  [RegionDBNew].[dbo].Account acc
		  INNER JOIN [RegionDBNew].[dbo].[AccountCharge] ach ON 
			ach.CalculationYear = YEAR(@дата) AND 
			ach.CalculationMonth = MONTH(@дата) AND ach.CalculationMonth = MONTH(@дата) AND
			ach.AccountID = acc.ID
		  LEFT JOIN [RegionDBNew].[dbo].UnitOfMeasure um ON ach.[UnitOfMeasureID] = um.ID
		  LEFT JOIN [RegionDBNew].[dbo].[ServiceUnderAccount] suc ON suc.ID = ach.ServiceUnderAccountID
		WHERE
		  acc.ID = @кодЛС
		ORDER BY 
		  suc.Title;
END

Запостил: sciner sciner, (Updated )

Комментарии (14) RSS

  • С таким приходилось работать, сопровождать и дописывать. Убеждал коллег думать прежде чем копипастить.
    - "мкей", отвечали они и продолжали ебошить.
    Даже не смешно.

    >ach.CalculationMonth = MONTH(@дата) AND ach.CalculationMonth = MONTH(@дата) AND
    АдЪ.
    Ответить
  • Начинать с запятых - никак не могу визуально это воспринять, выглядит уродско.
    Ну и упоротые алиасы, тоже сурово.
    Ответить
  • >ALTER PROCEDURE [dbo].[prodam_Получить_Начисления_По_ЛС]
    Не продаст. Надеюсь.
    Ответить
  • Откровенно говоря, вижу 3 проблемы:
    - архитектура базы хромает, раз за одними и теми же полями надо лазить в 3 разные таблицы
    - ужасный нейминг со смесью кириллицы и латиницы
    - бизнесс-алиасы полям задаются на уровне хранимы, а не на уровне юзер-интерфейса

    Из озвученного выше:
    - с запятыми перед полями жить можно и даже для дебага полезно (очень легко поставив -- исключить поле из выборки. Зачем вначале запятые ставить? Чаще изменения случаются с последними элементами, а не первыми)
    - 92 строку оптимизатор запросов все-равно преобразует в единое условие

    Итого, как заключение - бить надо рахитектора. Разработчик выкрутился, как смог. Если разработчик этого и является рахитектором решения - бить разработчика.
    Ответить
    • Жить-то можно, не спорю. Только это уныло слегка.
      Отлаживать комментированием - плохая практика.
      Ответить
  • >с запятыми перед полями жить можно и даже для дебага полезно
    Безусловно.

    > архитектура базы хромает, раз за одними и теми же полями надо лазить в 3 разные таблицы
    > Разработчик выкрутился, как смог
    Можно было не копипастить - создать сводную временную таблицу или если противник temp table(о ужас!) использовать exec
    Ответить
    • >использовать exec
      Или with какой-нибудь. В ms sql давно добавили.
      >[dbo].[prodam_Получить_Начисления_По_ЛС]
      > @кодЛС uniqueidentifier,
      > @дата date,
      > @источникНачислений nvarchar(50)
      Та это как в быдлоexcelе или 1C.
      Ответить
      • Хочу подчеркнуть, что для разработчика не специализирующегося на проектировании БД (отбросим знания with) написан запрос, с точки зрения _производительности_ - оптимально (временные таблицы - дополнительная перегонка данных, динамика - незакешированный запрос), с точки зрения _читабельности и повторяемости_ кода - плохо. Осуждать человека, написавшего данный запрос, не могу.
        Ответить
        • >временные таблицы - дополнительная перегонка данных, динамика - незакешированный запрос
          Да. Согласен. С точки зрения производительности оно-то оптимально, но там ошибиться просто негде.
          А как такое сопровождать?
          Программист оттачивает технику копипаста, и потом 16 раз такое накопировано, 32 раза итд?

          >динамика - незакешированный запрос
          В большинстве случаев это некритично, доли секунды на компиляцию планов стоят меньше чем труд программиста, которому потом поддерживать.

          >отбросим знания with
          Не надо. Они тут очень кстати.
          Ответить
          • Все верно сказано, но вернувшись к причинно-следственному анализу, повторюсь: первопричина данного ГК - кривая архитектура БД, не было бы такой кривой архитектуры - не было бы и данного ГК.
            ЗЫ Я там ошибку допустил - "незакешированный запрос" = "незакешированный план запроса", но меня поняли 😉
            ЗЗЫ И все-таки не стоит думать, что все знают динамику и конструкцию with.
            Ответить
            • >Я там ошибку допустил - "незакешированный запрос" = "незакешированный план запроса"

              Это я понял.
              Сборка запросов типична для ситуации когда в процедуру приходит несколько параметров @a,@b,@c,@d и нужна логика, если @a is null, то убрать условие на @a, если @b is null, то убрать джойн на @b.
              Тут видится джва выхода
              а) "оптимальный" копипаст на всё случаи жизни. в данном примере 16. скомпиленые планы и скорость прилагаются. проблемы возникают когда в процедуру надо добавить @e, а потом и @f.
              б) OR со всеми вытекающими union и 16 сканами по таблице (t1.someA=@a or @a is null).

              Тут-то на помощь и спешит динамика.
              Ответить

Добавить комментарий

Семь раз отмерь — один отрежь, guest!

    А не использовать ли нам bbcode?


    8