如果另一个值不存在,如何根据一个值从表中选择项目? (口才/ SQL) [英] How to select items from a table based on one value if another value does not exists? (eloquent/sql)
问题描述
块表
列:
| id | s lug |标题|语言|内容|
条目:
| 1 |首页|第一| en |第一块|
| 2 |首页|第一| nl | het eerste blok |
| 3 |首页|第二| en |第二块|
- >块第二不适用于'nl'语言
必需的输出
fallback language = zh
选择偏好语言= en,输出:
| 1 |首页|第一| en |第一块|
| 3 |首页|第二| en |第二块|
选择首选语言= nl,输出:
| 2 |首页|第一| nl | het eerste blok |
| 3 |首页|第二| en |第二块|
- >选择这个,因为'nl'版本不可用
目前我只是选择了所选择的首选语言,因为如果优先语言块不可用,我不知道如何选择后备语言块。我可以尝试运行两个语言的两个查询,然后合并它们,只要插入后备语言块,如果该块的标题数小于1,但这似乎是非常精致和不是很优雅的
对于我的应用程序,我使用雄辩:
$ blocks = Block :: - > where('slug','=','home')
- > whereIn('language',$ selectedLanguage)
- > get();
我如何在雄辩中做到这一点? (或在原始SQL中,为此)?
如果我正确理解你,如果已经有相同的 slug
和 title $的首选语言的行,则要使用后备语言删除行c $ c>。
您可以使用LEFT JOIN作为备用语言来检查是否存在具有优先语言的条目。例如,如果你喜欢的语言是nl,后备语言是en,你的查询可能如下所示:
select blocks *
从块
左连接块b1
在b1.slug = blocks.slug
和b1.title = blocks.title
和b1.language =' nl'
和blocks.language<> 'nl'
其中blocks.slug ='home'
和blocks.language('nl','en')
和b1.id为空
加入的单词可能是一样的:寻找一个更好的翻译相同的 slug
和标题
。如果该语言是首选的,则不会有匹配,因为 blocks.language<> NL
。否则,联盟将搜索优先翻译('b1.language ='nl'
)。
在WHERE子句中,我们只会在没有找到更好的翻译( b1.id为null
)的情况下返回行。
最好我可以将查询转换为雄辩是:
$ prefered ='nl';
$ fallback ='en';
$ blocks = App \Block :: where('blocks.slug','=','home')
- > whereIn('blocks.language',[$ (
- > leftJoin('blocks as b1',function($ join){
$ join-> on('b1.slug','=','blocks
- > on('b1.title','=','blocks.title')
- > on('b1.language','=',DB: :raw('?'))
- > on('blocks.language','',DB :: raw('?'))
;
} )
- > whereNull('b1.id')
- > addBinding([$ prefended,$ preference],'join')
- > select(DB :: raw ('blocks。*'))
- > get()
;
注意:我假设标题
对于所有语言的块是相同的。否则,您将需要另一列(如 block_id
)来标识块。
I have a table where I store different blocks of texts for my website. I am currently selecting the correct blocks for each page with the slug of the page, and the prefered language. I would like to select the same block of text (with the same title) in the fallback language when the prefered language is not available.
The blocks table
columns:
| id | slug | title | language | content |
entries:
| 1 | home | first | en | the first block |
| 2 | home | first | nl | het eerste blok |
| 3 | home | second | en | the second block |
--> block "second" not available for the 'nl' language
Required output
fallback language = en
selected prefered language = en, output:
| 1 | home | first | en | the first block |
| 3 | home | second | en | the second block |
selected prefered language = nl, output:
| 2 | home | first | nl | het eerste blok |
| 3 | home | second | en | the second block |
--> select this one, because the 'nl' version is not available
Currently I am only selecting the blocks with the selected prefered language, because I don't know how to approach this with selecting the 'fallback language' block if the 'prefered language' block is not available. I could try to run two queries for both languages, and then merge them somehow and only inserting the 'fallback language' blocks if the title count of this block is lower than 1, but this seems quite elaborate and not very elegant?
For my app I am using eloquent:
$blocks = Block::->where('slug', '=', 'home')
->whereIn('language', $selectedLanguage)
->get();
How could I do this in eloquent? (or in raw SQL, for that matter?)
If i understand you correctly, you want to "remove" the rows with the fallback language if there is already a row with the prefered language for the same slug
and title
.
You can use a LEFT JOIN for the fallback language to check if an entry with the prefered language exists. For example if your preferd language is 'nl' and the fallback language is 'en' your query could look like:
select blocks.*
from blocks
left join blocks b1
on b1.slug = blocks.slug
and b1.title = blocks.title
and b1.language = 'nl'
and blocks.language <> 'nl'
where blocks.slug = 'home'
and blocks.language in ('nl', 'en')
and b1.id is null
The join in words could be somthing like: Look for a better translation for the same slug
and title
. If the language is the prefered one there won't be a match because of blocks.language <> 'nl'
. Otherwise the join will "search" for the prefered translation ('b1.language = 'nl'
).
In the WHERE clause we tell only to return rows if no better translation has been found (b1.id is null
).
Best i could do to convert the query to eloquent is:
$prefered = 'nl';
$fallback = 'en';
$blocks = App\Block::where('blocks.slug', '=', 'home')
->whereIn('blocks.language', [$prefered, $fallback])
->leftJoin('blocks as b1', function($join) {
$join->on('b1.slug', '=', 'blocks.slug')
->on('b1.title', '=', 'blocks.title')
->on('b1.language', '=', DB::raw('?'))
->on('blocks.language', '<>', DB::raw('?'))
;
})
->whereNull('b1.id')
->addBinding([$prefered, $prefered], 'join')
->select(DB::raw('blocks.*'))
->get()
;
Note: I'm assuming that title
is the same for a block in all languages. Otherwise you would need another column (like block_id
) to identify a block.
这篇关于如果另一个值不存在,如何根据一个值从表中选择项目? (口才/ SQL)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!