草庐IT

php - MySQL EAV SELECT 一对多单行结果

coder 2023-10-20 原文

我在这里看到过类似的问题,但没能找到符合我的具体情况的问题。我有以下三个表:

content
id, [other fields]

attributes
id, title

attributes_values
id, attribute_id[foreign to attributes.id], content_id[foreign to content.id], value

我想要的是可以返回适当数据的单个查询(或一组子查询),以避免在编程中对其进行操作。

有关表格的更多信息:属性具有三个记录(型号编号、零件编号和在购物车中显示)。

我需要从内容中选择购物车中显示的 attribute_value = 1 的所有记录。与此同时,我希望将其他相关的 attribute_values 作为其相关的 attribute.title 返回。结果看起来像这样:

id    [other fields]    Model # [from attributes.title field]    Part # [from attributes.title field]
1     [any data]        value from attributes_values             value from attributes_values
2     [any data]        value from attributes_values             value from attributes_value

到目前为止,我完成此操作的唯一方法不是很优雅,因为我必须对同一个表进行多个连接:

SELECT * FROM content AS a
LEFT JOIN attributes_values AS b ON (b.content_id = a.id AND b.attribute_id = [Model # ID])
LEFT JOIN attributes_values AS c ON (c.content_id = a.id AND c.attribute_id = [Part # ID])
WHERE a.id IN (
    SELECT content_id FROM attributes_values WHERE attribute_id = [Show in Cart ID] AND value = 1
)

如您所见,我必须将相关键硬编码到 JOIN 语句中,这不会使其具有很好的可扩展性(而且感觉很脏)。

一些最后的注意事项:我正在使用 PHP 和 Joomla!,所以如果这会影响您的回答(或者如果有一些 secret 的 Joomla 提示),请随时将其包括在内。此外,这是一个我无法更改的预先建立的表架构,因此我需要针对上述表的查询解决方案,而不是关于更好的表设计的建议。

任何帮助将不胜感激。

干杯!

最佳答案

您可以将 MAX() 等聚合函数与 CASE WHEN 语句结合使用,而不是为每个属性多次连接您的表:

SELECT
  content.id,
  [other_fields],
  MAX(CASE WHEN attributes.title='Model #' THEN attributes_values.value END) AS Model_N,
  MAX(CASE WHEN attributes.title='Part #' THEN attributes_values.value END) AS Part_N
FROM
  content INNER JOIN attributes_values
  ON content.id = attributes_values.content_id
  INNER JOIN attributes
  ON attributes_values.attribute_id = attributes.id
GROUP BY
  id,
  [other_fields]
HAVING
  MAX(CASE WHEN attributes.title='Show in Cart' THEN attribute_values.value END)='1'

一点解释:

CASE WHEN attributes.title='Model #' THEN attributes.value END

当属性为“Model #”时将返回值,否则返回 NULL,并且

MAX(...)

将返回最大的非 NULL 值,即 attributes.title='Model #' 的值。

动态属性

MySQL 没有 Pivot 函数,所以如果你想让你的列表是动态的,你必须动态地创建一个包含所有属性的 SQL 字符串并执行这个字符串。

您可以从attributes 表中获取所有属性:

SELECT
    CONCAT(
      'MAX(CASE WHEN attributes.title=''',
      REPLACE(attributes.title, '''', ''''''),
      ''' THEN attributes_values.value END) AS `',
      REPLACE(attributes.title, '`', '``'),
      '`'
    )
FROM
  attributes;

并使用 GROUP_CONCAT 将所有内容组合在一起:

SELECT GROUP_CONCAT(...the concat above...)
FROM attributes;

所以你的最终查询将是这样的:

SELECT
  CONCAT('SELECT content.id,',

  GROUP_CONCAT(
    CONCAT(
      'MAX(CASE WHEN attributes.title=''',
      REPLACE(attributes.title, '''', ''''''),
      ''' THEN attributes_values.value END) AS `',
      REPLACE(attributes.title, '`', '``'),
      '`'
    )
  ),

  ' FROM content INNER JOIN attributes_values ',
  'ON content.id = attributes_values.content_id ',
  'INNER JOIN attributes ',
  'ON attributes_values.attribute_id = attributes.id ',
  'GROUP BY id HAVING ',
  'MAX(CASE WHEN attributes.title=''Show in Cart'' THEN attributes_values.value END)=''1'''
  )
FROM
  attributes
INTO @SQL;

现在@SQL 变量将保存要执行的查询的值,您可以执行它:

PREPARE stmt FROM @sql;
EXECUTE stmt;

这里唯一的问题是 GROUP_CONCAT 有一个 maximum length limit ,如果您的表包含许多属性,您可以增加它。

请看一个例​​子 fiddle here .

关于php - MySQL EAV SELECT 一对多单行结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29394852/

有关php - MySQL EAV SELECT 一对多单行结果的更多相关文章

  1. 报告回顾丨模型进化狂飙,DetectGPT能否识别最新模型生成结果? - 2

    导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri

  2. ruby - 在 Ruby 数组中收集重复项的最快/单行方法? - 2

    像这样转换数组的最快/单行方法是什么:[1,1,1,1,2,2,3,5,5,5,8,13,21,21,21]...进入像这样的对象数组:[{1=>4},{2=>2},{3=>1},{5=>3},{8=>1},{13=>1},{21=>3}] 最佳答案 要获得所需的格式,您可以附加一个调用以映射到您的解决方案:array.inject({}){|h,v|h[v]||=0;h[v]+=1;h}.map{|k,v|{k=>v}}虽然它仍然是单行的,但它开始变得凌乱了。 关于ruby-在Ruby

  3. ruby-on-rails - 这个 C 和 PHP 程序员如何学习 Ruby 和 Rails? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它

  4. ruby - gem 推送结果为 "package metadata is missing" - 2

    我正在尝试将我更新的gem推送到ruby​​gems.com并得到以下结果。~/dev/V2/V2GPTI(master)$gembuildv2gpti.gemspecSuccessfullybuiltRubyGemName:v2gptiVersion:0.2File:v2gpti-0.2-universal-darwin-13.gem~/dev/V2/V2GPTI(master)$gempushv2gpti.gemspecERROR:Whileexecutinggem...(Gem::Package::FormatError)packagemetadataismissinginv2g

  5. ruby-on-rails - 如何添加具有额外列的多对多记录 - 2

    我有以下模型用户has_many:users_contactshas_many:contacts,through::users_contactsaccepts_nested_attributes_for:contacts,allow_destroy:true联系方式has_many:users_contactshas_many:users,through::users_contactsaccepts_nested_attributes_for:users_contacts,allow_destroy:true用户联系belongs_to:usersbelongs_to:contacts

  6. ruby - 猴子修补 float 中缀运算符产生意想不到的结果 - 2

    重新定义Float#/似乎没有效果:classFloatdef/(other)"magic!"endendputs10.0/2.0#=>5.0但是当另一个中缀运算符Float#*被重新定义时,Float#/突然采用了新的定义:classFloatdef/(other)"magic!"enddef*(other)"spooky"endendputs10.0/2.0#=>"magic!"我很想知道是否有人可以解释这种行为的来源,以及其他人是否得到相同的结果。ruby:ruby2.0.0p353(2013-11-22)[x64-mingw32]要快速确认错误,请运行thisscript.

  7. ruby-on-rails - 尝试编辑时,Rails form_for 结果为 POST 而不是 PUT - 2

    我正在使用Rails4并遇到以下错误。RoutingErrorNoroutematches[POST]"/logs/1/meals/13/edit我正在使用:meal传递模型对象的form_for,并且编辑页面正确呈现。但是,Rails似乎并没有检查膳食对象是否已经保存,因此它一直尝试将表单发送到#create操作并尝试发出POST请求,而不是将表单发送到更新操作并进行当我点击提交时一个PUT请求。我如何让form_for识别我正在尝试更新现有对象并且需要PUT而不是POST?其他一切正常,我已经运行了所有迁移。我是Rails的新手,几乎一整天都在尝试自己解决这个问题。请帮忙!请注意,

  8. ruby - 为什么会.is_a?和 .class 给出相互矛盾的结果? - 2

    我有三个属于同一个类的对象。一个是通过Item.new创建的,另外两个是从数据库(Mongoid)中提取的。我将这些对象中的一个/任何一个传递给另一个方法,并通过is_a?检查该方法中的类型:definitialize(item,attrs=nil,options=nil)super(attrs,options)raise'invaliditemobject'unlessitem.is_a?(Item)好吧,这次加薪被击中了。所以我在Rails控制台中检查类、is_a和instance_of。我得到相互矛盾的结果。为什么它们有相同的class但只有其中一个是那个class的instan

  9. ruby - 带有位串的意外解包结果 - 2

    为什么当我打开irb并运行时放'A'.unpack("B8")我得到01000001但是当我运行放'A'.unpack("B4B4")我只得到0100而不是[0100,0001]?unpack的分辨率是不是只有一个完整的字节?一点都不差? 最佳答案 让我们做一些测试来理解行为:>'A'.unpack('B8')=>["01000001"]它返回char'A'的8个最高有效位(MSB)>'A'.unpack('B4')=>["0100"]它返回char'A'的4MSBs>'A'.unpack('B16')=>["01000001"]它

  10. ruby - 为什么我会看到这两个几乎相同的 Ruby 正则表达式模式的不同结果,为什么一个匹配我认为不应该匹配的内容? - 2

    使用Ruby1.9.2,我在IRB中有以下Ruby代码:>r1=/^(?=.*[\d])(?=.*[\W]).{8,20}$/i>r2=/^(?=.*\d)(?=.*\W).{8,20}$/i>a=["password","1password","password1","pass1word","password1"]>a.each{|p|puts"r1:#{r1.match(p)?"+":"-"}\"#{p}\"".ljust(25)+"r2:#{r2.match(p)?"+":"-"}\"#{p}\""}这会产生以下输出:r1:-"password"r2:-"password"r1:

随机推荐