在模板函数参数之间强制实现所需的关系(Enforcing desired relationship between template function parameters)
我正在努力改进内部消息库,旨在在我们的应用程序内部发送消息,以及外部消费者。 消息由
MessageType
(enum class
)和一些数据(struct
)组成。 每个MessageType::
对应于特定的数据类型(例如,MessageType::TypeA
将始终包含Foo
)。 但是,多种消息类型可以使用相同的结构(例如,MessageType::TypeM
也可以使用Foo
)。我们有一个可以发送消息的类。 我们之前的消息发送者类实现为每种类型定义了一个方法:
SendMessageTypeA(Foo data) SendMessageTypeB(Bar data) SendMessageTypeM(Foo data)
当有大量消息时,这可能导致大量代码重复(方法体基本相同,但不同的参数类型除外)。
我已经实现了一个新方法:
template<typename structType> void Send(MessageType msgType, const structType & messageData)
此单一方法可以发送任何消息,具体取决于提供的相应模板参数。 请注意,
MessageType
在编译时始终是已知的。问题是这个新方法不强制
MessageType
和struct
之间的关系。 例如,Send<Foo>(MessageType::TypeB, data)
将编译,即使MessageType::TypeB
应包含Bar
。 将在运行时检测到不匹配,但我想使其成为编译时错误。我不知道如何实现这一目标。 我考虑过:
- 声明所有
SendMessageX()
方法,并使用它们来调用Send<MessageX>()
。 这确实减少了重复,但每次定义消息时我仍然需要创建一个新方法。- 试图使用
static_assert
来捕捉不匹配。 我不确定如何将MessageType
映射到他们想要的struct
。- 我正在咆哮错误的树
I'm working on improving an in-house messaging library, designed to send messages internally within our applications, and to external consumers. A message consists of a
MessageType
(enum class
) and some data (struct
). EachMessageType::
corresponds to a particular data type (e.g.,MessageType::TypeA
will always containFoo
). However, multiple message types could use the same struct (e.g.,MessageType::TypeM
could also useFoo
).We have a class that can send messages. Our previous implementation of the message sender class defines a method for each type:
SendMessageTypeA(Foo data) SendMessageTypeB(Bar data) SendMessageTypeM(Foo data)
When there are lots of messages, this can result in a lot of code duplication (the method body is essentially the same, with the exception of the different parameter types).
I've implemented a new method:
template<typename structType> void Send(MessageType msgType, const structType & messageData)
This single method can send any message, depending on the appropriate template parameter being provided. Note that the
MessageType
is always known at compile time.The problem is that this new method does not enforce the relationship between
MessageType
andstruct
. For example,Send<Foo>(MessageType::TypeB, data)
will compile, even thoughMessageType::TypeB
should containBar
. The mismatch will be detected at runtime, but I'd like to make it a compile time error.I'm not sure how to achieve this. I've considered:
- Declaring all the
SendMessageX()
methods, and use them to callSend<MessageX>()
. This does reduce the duplication, but I still have to create a new method every time a message is defined.- Attempting to use
static_assert
to catch the mismatch. I'm not sure how to mapMessageType
s to their desiredstruct
.- I'm barking up the wrong tree
原文:https://stackoverflow.com/questions/39760704
最满意答案
为什么OP查询返回错误1054
返回的错误是因为从UNION的结果中分配给列的名称取自第一个SELECT。
您可以通过运行一个简单的示例来观察:
SELECT 1 AS one UNION SELECT 2 AS two
该查询返回的结果集将包含单个列,分配给该列的名称将为
one
,即第一个SELECT中的列名称。 这解释了为什么从查询中收到错误的原因。
返回没有匹配的行的一种方法
要返回
table1
中col1
值,该值与table2
col1
列中的任何值都不匹配...使用反连接模式的一个选项...
SELECT t1.col1 FROM table1 t1 LEFT JOIN table2 t2 ON t2.col1 = t1.col1 WHERE t2.col1 IS NULL
LEFT JOIN
操作返回table1中的所有行,以及table2中找到的任何“匹配”行。 “技巧”是WHERE子句中的谓词...来自table2的任何“匹配”行将在col1中具有非NULL值。 因此,如果我们排除了找到匹配项的所有行,那么我们会留下table1中没有匹配项的行。如果我们想从
table2
中获取table1
没有“匹配”行的行,我们可以执行相同的操作,只需翻转表的顺序即可。如果我们组合这两个集合,但只想要一个“不匹配”值的“不同”列表,我们可以使用
UNION
集合运算符:SELECT t1.col1 FROM table1 t1 LEFT JOIN table2 t2 ON t2.col1 = t1.col1 WHERE t2.col1 IS NULL UNION SELECT s2.col1 FROM table2 s2 LEFT JOIN table1 s1 ON s1.col1 = s2.col1 WHERE s1.col1 IS NULL
-
找出不匹配值来自哪个表
有时,我们想知道哪个查询返回了值; 我们可以通过在每个查询中包含一个文字值作为鉴别器来实现。
SELECT 'table1' AS src , t1.col1 FROM table1 t1 LEFT JOIN table2 t2 ON t2.col1 = t1.col1 WHERE t2.col1 IS NULL UNION SELECT 'table2' AS src , s2.col1 FROM table2 s2 LEFT JOIN table1 s1 ON s1.col1 = s2.col1 WHERE s1.col1 IS NULL ORDER BY 2
查找不匹配行的不同(通常性能较差)方法
一个完全不同的方法,返回一个等效的结果,将做这样的事情:
SELECT q.col1 FROM ( SELECT 't1' AS src, t1.col1 FROM table1 t1 UNION SELECT 't2' AS src, t2.col1 FROM table2 t2 ) q GROUP BY q.col1 HAVING COUNT(DISTINCT q.src) < 2 ORDER BY q.col1
(内联视图
q
将被“物化”为派生表,因此这种方法对于大型集合来说可能是昂贵的,并且这种方法不会利用col1
上的索引来执行匹配。)另外一个小的区别是反连接方法:如果两个表中都存在NULL,则将省略col1值NULL。 除此之外,结果集是等效的。Why Error 1054 is being returned by OP query
The error that's being returned is because the name assigned to a column from the result of a UNION is taken from the first SELECT.
You can observe this by running a simple example:
SELECT 1 AS one UNION SELECT 2 AS two
The resultset returned by that query will contain a single column, the name assigned to the column will be
one
, the column name from the first SELECT. This explains why you are getting the error from your query.
One way to return rows with no match
To return values of
col1
fromtable1
which do not match any value in thecol1
column fromtable2
...one option to use an anti-join pattern...
SELECT t1.col1 FROM table1 t1 LEFT JOIN table2 t2 ON t2.col1 = t1.col1 WHERE t2.col1 IS NULL
The
LEFT JOIN
operation returns all rows from table1, along with any "matching" rows found in table2. The "trick" is the predicate in the WHERE clause... any "matching" rows from table2 will have a non-NULL value in col1. So, if we exclude all of the rows where we found a match, we're left with rows from table1 that didn't have a match.If we want to get rows from
table2
that don't have a "matching" row intable1
, we can do the same thing, just flipping the order of the tables.If we combine the two sets, but only want a "distinct" list of "not matched" values, we can use the
UNION
set operator:SELECT t1.col1 FROM table1 t1 LEFT JOIN table2 t2 ON t2.col1 = t1.col1 WHERE t2.col1 IS NULL UNION SELECT s2.col1 FROM table2 s2 LEFT JOIN table1 s1 ON s1.col1 = s2.col1 WHERE s1.col1 IS NULL
--
Finding out which table the non-matched value is from
Sometimes, we want to know which query returned the value; we can get that by including a literal value as a discriminator in each query.
SELECT 'table1' AS src , t1.col1 FROM table1 t1 LEFT JOIN table2 t2 ON t2.col1 = t1.col1 WHERE t2.col1 IS NULL UNION SELECT 'table2' AS src , s2.col1 FROM table2 s2 LEFT JOIN table1 s1 ON s1.col1 = s2.col1 WHERE s1.col1 IS NULL ORDER BY 2
A different (usually less performant) approach to finding non-matching rows
An entirely different approach, to returning an equivalent result, would be do something like this:
SELECT q.col1 FROM ( SELECT 't1' AS src, t1.col1 FROM table1 t1 UNION SELECT 't2' AS src, t2.col1 FROM table2 t2 ) q GROUP BY q.col1 HAVING COUNT(DISTINCT q.src) < 2 ORDER BY q.col1
(The inline view
q
will be "materialized" as a derived table, so this approach can be expensive for large sets, and this approach won't take advantage of indexes oncol1
to perform the matching.) One other small difference between this and the anti-join approach: this will omit a col1 value of NULL if a NULL exists in both tables. Aside from that, the resultset is equivalent.
相关问答
更多-
你可以把所有东西都包装在一个SELECT并用你想要的别名来包装这个列。 select a as [b] -- just alias it here with whatever you want from ( select 1 as a union select 2 as b ...) result_set 但正如@威尔所说,它就是这样,不能改变这一点。 要么: 只需确保在顶部使用带有“别名”的查询,并使用包含其他查询/值的单个SELECT语句使用UNION 。 sel ...
-
PDO UNION用?(PDO UNION with ? not working)[2023-11-16]
你用两个参数调用查询(比如在第一个Query中,在第二个查询中),即使它们具有相同的值..所以你必须传递两个参数 $qResults->execute([$c1, $c1]); You invoke the query with two parameters (like in the first Query and like in the second) even if they have the same value .. so you have to pass two parameters $qRes ... -
使用UNION和UNION ALL设置运算符,结果集的列名称在第一个SELECT中指定。 将忽略后续查询中的列名和别名。 (无法为结果集中的一列指定两个不同的别名。每个列都会分配一个名称。) 但是对于您的结果,您不一定需要UNION ALL操作。 看起来您想要在同一行上的每个状态的数量的和。 您可以使用条件聚合。 例如: SELECT i.item_name , r.item_version , SUM(IF(r.group_status=1,r.quantity,0)) AS `App ...
-
为什么OP查询返回错误1054 返回的错误是因为从UNION的结果中分配给列的名称取自第一个SELECT。 您可以通过运行一个简单的示例来观察: SELECT 1 AS one UNION SELECT 2 AS two 该查询返回的结果集将包含单个列,分配给该列的名称将为one ,即第一个SELECT中的列名称。 这解释了为什么从查询中收到错误的原因。 返回没有匹配的行的一种方法 要返回table1中col1值,该值与table2 col1列中的任何值都不匹配... 使用反连接模式的一个选项 ...
-
您需要为派生表提供一个别名,如下所示: SELECT * from (SELECT column1, 'table1' from table1 UNION SELECT column1, 'table2' from table2 UNION SELECT column1, 'table3' from table3) dtAlias WHERE column1 not like 'abr%' and length(column1) < 8; You need to give the de ...
-
我不确定,但它看起来好像你想要一个视图 。 像这样定义该查询: CREATE VIEW MyMessageView AS SELECT ... FROM ... ... 现在,您可以在可以使用普通表的任何上下文中使用该视图:在FROM子句中,在JOIN子句中,作为子查询等: SELECT ... FROM MyMessageView WHERE ... ... UNION SELECT ... FROM MyMessageView WHERE ... I am answering my own que ...
-
这是因为在WHERE之前执行SELECT并且在WHERE之前执行FROM ,因此它不能在第二个查询中使用,但它可以在第一个查询中使用。 This is because the SELECT is executed after the WHERE and the FROM is executed before the WHERE so it cannot be used in the second query but it can be used in that first query.
-
我试过了,它对我来说很好。 但是,这是对SQL的建议更改,这可能会有所帮助。 SELECT Title AS [SAL], FirstName AS [FIRSTNAME], MiddleName AS [MIDDLENAME] FROM dbo.Employee I have tried it and it works fine for me. However, here is a suggested change to your SQL which may assist. ...
-
您可以使用公用表表达式或子查询将FName创建为新结果集的一种虚拟列。 您可以将结果集用作一种虚拟表,并在where子句中对其进行过滤。 SELECT * FROM ( SELECT LastName , Company , Status , CASE WHEN NickName IS NULL OR NickName = '' THEN FirstName ELSE NickName END AS FName FROM d ...
-
select union构建一个结果表,一个表只能有一个列名,所以你不能为同一个列名指定不同的别名..因此sql只返回第一个 你不能通过这种方式从联合中获得不同的别名 相反,您可以使用适当的值标记每个值 $channeldetectquery = "(SELECT 'amazon' as source, SKU FROM amazonlistings WHERE SKU = '$channelskuarray[$i]') UNION (SELECT 'ebay', SKU FROM eba ...