Неизвестный столбец в разделе where, но столбцы указаны в select [duplicate]

Spark 2.1 +

Вы можете использовать функцию from_json :

import org.apache.spark.sql.functions.from_json
import org.apache.spark.sql.types._

val schema = StructType(Seq(
  StructField("k", StringType, true), StructField("v", DoubleType, true)
))

df.withColumn("jsonData", from_json($"jsonData", schema))

Spark 1.6 +

Вы можете используйте get_json_object, который берет столбец и путь:

import org.apache.spark.sql.functions.get_json_object

val exprs = Seq("k", "v").map(
  c => get_json_object($"jsonData", s"$$.$c").alias(c))

df.select($"*" +: exprs: _*)

и извлекает поля для отдельных строк, которые могут быть добавлены к ожидаемым типам.

Аргумент path выраженный с использованием точечного синтаксиса, с ведущим $., обозначающим корень документа (поскольку используемый выше код использует интерполяцию строк $, поэтому $$.).

Spark & ​​lt; = 1.5:

Возможно ли это?

Насколько я знаю, это невозможно. Вы можете попробовать что-то похожее на это:

val df = sc.parallelize(Seq(
  ("1", """{"k": "foo", "v": 1.0}""", "some_other_field_1"),
  ("2", """{"k": "bar", "v": 3.0}""", "some_other_field_2")
)).toDF("key", "jsonData", "blobData")

Я предполагаю, что поле blob не может быть представлено в JSON. В противном случае вы откажитесь от разделения и соединения:

import org.apache.spark.sql.Row

val blobs = df.drop("jsonData").withColumnRenamed("key", "bkey")
val jsons = sqlContext.read.json(df.drop("blobData").map{
  case Row(key: String, json: String) =>
    s"""{"key": "$key", "jsonData": $json}"""
}) 

val parsed = jsons.join(blobs, $"key" === $"bkey").drop("bkey")
parsed.printSchema

// root
//  |-- jsonData: struct (nullable = true)
//  |    |-- k: string (nullable = true)
//  |    |-- v: double (nullable = true)
//  |-- key: long (nullable = true)
//  |-- blobData: string (nullable = true)

Альтернативный (более дешевый, хотя и более сложный) подход - использовать UDF для разбора JSON и вывода столбца struct или map. Например, что-то вроде этого:

import net.liftweb.json.parse

case class KV(k: String, v: Int)

val parseJson = udf((s: String) => {
  implicit val formats = net.liftweb.json.DefaultFormats
  parse(s).extract[KV]
})

val parsed = df.withColumn("parsedJSON", parseJson($"jsonData"))
parsed.show

// +---+--------------------+------------------+----------+
// |key|            jsonData|          blobData|parsedJSON|
// +---+--------------------+------------------+----------+
// |  1|{"k": "foo", "v":...|some_other_field_1|   [foo,1]|
// |  2|{"k": "bar", "v":...|some_other_field_2|   [bar,3]|
// +---+--------------------+------------------+----------+

parsed.printSchema

// root
//  |-- key: string (nullable = true)
//  |-- jsonData: string (nullable = true)
//  |-- blobData: string (nullable = true)
//  |-- parsedJSON: struct (nullable = true)
//  |    |-- k: string (nullable = true)
//  |    |-- v: integer (nullable = false)

152
задан OMG Ponies 26 April 2011 в 04:05
поделиться

8 ответов

Вы можете использовать только псевдонимы столбцов в предложениях GROUP BY, ORDER BY или HAVING.

Стандартный SQL не позволяет ссылаться на псевдоним столбца в предложении WHERE. Это ограничение наложено, потому что, когда выполняется код WHERE, значение столбца еще не может быть определено.

Скопировано из Документация MySQL

Как указано в комментариях, использование HAVING вместо этого может выполнить эту работу. Обязательно прочитайте это WHERE vs HAVING .

355
ответ дан Community 18 August 2018 в 10:19
поделиться
  • 1
    +1 для ref (и точности) – Jonathan Fingland 3 June 2009 в 01:40
  • 2
    Приветствия за быстрый и точный ответ! Я просмотрел предложение HAVING и разработал способ успешного выполнения этого запроса. Еще раз спасибо. – James 3 June 2009 в 01:42
  • 3
    В случае, если у кого-то еще такая же проблема, как у меня, которая использовала псевдонимы col в аргументе where, который не выполнялся, - заменив «WHERE» на «HAVING», сразу установив +1 хороший ответ. – megaSteve4 28 May 2012 в 01:14
  • 4
    @ megaSteve4 У меня была такая же проблема! Использование & quot; HAVING & quot; решила его гладко. :) – Johan 3 May 2013 в 00:02
  • 5
    Это может быть или не быть важным в вашем случае, но HAVING выполняется медленнее, чем WHERE – DTs 25 April 2014 в 09:38

Возможно, мой ответ слишком поздний, но это может помочь другим.

Вы можете заключить его в другой оператор select и использовать в нем предложение where.

SELECT * FROM (Select col1, col2,...) as t WHERE t.calcAlias > 0

calcAlias ​​- это столбец псевдонимов, который был рассчитан.

10
ответ дан George Khouri 18 August 2018 в 10:19
поделиться
  • 1
    Хороший и короткий, но это слишком расплывчато, чтобы быть полезным. – Agamemnus 31 December 2014 в 01:53
  • 2
    @Agamemnus, Что вы подразумеваете под этим? – Pacerier 9 April 2015 в 21:36
  • 3
    Вопрос состоял в том, что «почему я не могу использовать поддельный столбец в предложении where того же запроса БД?» Этот ответ не отвечает на этот вопрос и не хватает глагола. – Agamemnus 9 April 2015 в 23:20
  • 4
    Тогда просто используйте ПОМОЩЬ – Hett 14 April 2015 в 09:40

Вы можете использовать предложение HAVING для фильтра, рассчитанного в полях SELECT и псевдонимах

7
ответ дан Hett 18 August 2018 в 10:19
поделиться
  • 1
    Я только что нашел Америку через год после тебя. Кредит принадлежит вам: D – Phung D. An 11 May 2015 в 20:23
  • 2
    @ fahimg23 - Не уверен. Я пытался найти причину, но не могу! Однако имейте в виду различия между WHERE и HAVING. Они не идентичны. stackoverflow.com/search?q=where+vs+having – rinogo 22 June 2017 в 21:05
  • 3
    UPDATE: Это потому, что этот ответ предоставляет одно и то же решение, но с дополнительной информацией. – rinogo 22 June 2017 в 21:07

Стандартный SQL (или MySQL) не позволяет использовать псевдонимы столбцов в предложении WHERE, потому что

при вычислении предложения WHERE значение столбца может еще не определено.

(из документации MySQL ). Вы можете вычислить значение столбца в предложении WHERE , сохранить значение в переменной и использовать его в списке полей. Например, вы можете сделать это:

SELECT `users`.`first_name`, `users`.`last_name`, `users`.`email`,
@postcode AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
WHERE (@postcode := SUBSTRING(`locations`.`raw`,-6,4)) NOT IN
(
 SELECT `postcode` FROM `postcodes` WHERE `region` IN
 (
  'australia'
 )
)

Это позволяет избежать повторения выражения, когда оно усложняется, что упрощает его работу.

17
ответ дан Joni 18 August 2018 в 10:19
поделиться
  • 1
    Разве это не противоречит документации , которая гласит: "Как правило, вы никогда не должны присваивать значение переменной пользователя и читать значение в пределах одного и того же оператора. Вы можете получить ожидаемые результаты, но это не гарантируется. & Quot; ? – Arjan 19 November 2014 в 09:58
  • 2
    Это определенно нужно иметь в виду. Это всегда срабатывало для меня, я думаю, что порядок оценки различных частей отчета должен был быть исправлен (сначала WHERE, затем SELECT, затем GROUP BY, ...), но у меня нет ссылки для этого – Joni 21 November 2014 в 07:44
  • 3
    Несколько примеров: некоторые претензии , что для них select @code:=sum(2), 2*@code работает в MySQL 5.5, но для меня в 5.6 второй столбец дает NULL при первом вызове и возвращает 2 раза предыдущий результат при повторном запуске. Интересно, что оба варианта @code:=2, 2*@code и select @code:=rand(), 2*@code действительно работают в моем 5.6 (сегодня). Но они действительно записывают и читают в предложении SELECT; в вашем случае вы устанавливаете его в ГДЕ. – Arjan 21 November 2014 в 08:59
  • 4
    @Joni, Почему бы просто не оценить состояние дважды? Разумеется, MySQL достаточно умен, чтобы оптимизировать это ....... – Pacerier 9 April 2015 в 21:37
  • 5
    @Pacerier, чтобы повторить выражение еще хуже, особенно если это сложно. Я не смог подтвердить, реализует ли MySQL общее исключение подвыражения. – Joni 12 April 2015 в 18:22

Я использую mysql 5.5.24, и работает следующий код:

select * from (
SELECT `users`.`first_name`, `users`.`last_name`, `users`.`email`,
SUBSTRING(`locations`.`raw`,-6,4) AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
) as a
WHERE guaranteed_postcode NOT IN --this is where the fake col is being used
(
 SELECT `postcode` FROM `postcodes` WHERE `region` IN
 (
  'australia'
 )
)
1
ответ дан Mike Chamberlain 18 August 2018 в 10:19
поделиться

Стандартный SQL запрещает ссылки на псевдонимы столбцов в предложении WHERE. Это ограничение наложено, потому что, когда вычисляется предложение WHERE, значение столбца может еще не определено. Например, следующий запрос является незаконным:

SELECT id, COUNT (*) AS cnt FROM tbl_name WHERE cnt> 0 GROUP BY id;

0
ответ дан Pavan Rajput 18 August 2018 в 10:19
поделиться

Как отметил Виктор, проблема связана с псевдонимом. Этого можно избежать, поставив выражение непосредственно в предложение WHERE x IN y:

SELECT `users`.`first_name`,`users`.`last_name`,`users`.`email`,SUBSTRING(`locations`.`raw`,-6,4) AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
WHERE SUBSTRING(`locations`.`raw`,-6,4) NOT IN #this is where the fake col is being used
(
 SELECT `postcode` FROM `postcodes` WHERE `region` IN
 (
  'australia'
 )
)

Однако, я думаю, это очень неэффективно, так как подзапрос должен выполняться для каждой строки внешний запрос.

23
ответ дан rodion 18 August 2018 в 10:19
поделиться
  • 1
    @rodion, Да, я считаю, что сильно медленный и неэффективный. – Pacerier 9 April 2015 в 21:31

Вы можете использовать SUBSTRING (locations. raw, - 6,4), где условие

SELECT `users`.`first_name`, `users`.`last_name`, `users`.`email`,
SUBSTRING(`locations`.`raw`,-6,4) AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
WHERE SUBSTRING(`locations`.`raw`,-6,4) NOT IN #this is where the fake col is being used
(
SELECT `postcode` FROM `postcodes` WHERE `region` IN
(
 'australia'
)
)
0
ответ дан Sameera Prasad Jayasinghe 18 August 2018 в 10:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: