Simplifying the boolean expression: (A ∧ ¬C) ∨ (B ∧ C) ∨ (A ∧ B) - boolean-logic

Suppose I have the following logical expression: (A ∧ ¬C) ∨ (B ∧ C) ∨ (A ∧ B)
Why does this simplify to (A ∧ ¬C) ∨ (B ∧ C)?
The truth tables are the same but I cannot get to the second expression with my current knowledge of the laws.

Here's how to reduce AC' + BC + AB to AC' + BC:
AC' + BC + AB
= AC' + BC + AB (C + C') -- C + C' = 1
= AC' + BC + ABC + ABC' -- distribute
= AC' + ABC' + BC + ABC -- rearrange
= AC' (1 + B) + BC (1 + A) -- factorize
= AC' + BC -- 1 + X = 1
Shoutout to jq170727 for helping me arrive at the solution.
The truth table for AC' + BC + AB is:
C A B | Y
------+---
0 0 0 | 0
0 0 1 | 0
0 1 0 | 1
0 1 1 | 1
1 0 0 | 0
1 0 1 | 1
1 1 0 | 0
1 1 1 | 1
Hence, the Karnaugh map for it is:
| A'B'| A'B | A B | A B'
---+-----+-----+-----+-----
C'| 0 | 0 | (1 | 1)
C | 0 | [1 | 1] | 0
As you can see, there are only two group which I've clearly marked with parentheses and square brackets respectively. Note that we do not group the elements of the A B column together because all its elements are already in groups. Thus, the result is AC' + BC.

Related

Can these two SQL queries be combined?

I'm wondering if there's a way I can combine these two queries into one? I need to get the mean and std dev for each column in the company_feature table. I then need to take those two values and use them in an aggregation query on each row in the company_feature table.
/* Get mean and std dev for each feature column */
SELECT
AVG(F1) AS F1_mean,
STDDEV(F1) AS F1_std_dev
FROM company_feature_test cft;
/* Add averages for each feature to the following query */
SELECT
DATA.company_id,
(
CASE
WHEN DATA.in_ref_set = 0 AND DATA.size = 'SMALL'
THEN
1 * ((LN(DATA.F1 + 1) - :F1_mean) / :F1_std_dev ) * 1
WHEN DATA.in_ref_set = 0 AND DATA.size = 'MEDIUM'
THEN
2 * ((LN(DATA.F1 + 1) - :F1_mean) / :F1_std_dev ) * 2
WHEN DATA.in_ref_set = 0 AND DATA.size = 'LARGE'
THEN
3 * ((LN(DATA.F1 + 1) - :F1_mean) / :F1_std_dev ) * 3
WHEN DATA.in_ref_set = 0 AND DATA.size = 'VERY_LARGE'
THEN
4 * ((LN(DATA.F1 + 1) - :F1_mean) / :F1_std_dev ) * 4
ELSE
5 * ((LN(DATA.F1 + 1) - :F1_mean) / :F1_std_dev )
END
) AS feature_1
FROM (
SELECT company.in_ref_set, company.size, cft.*
FROM company_feature_test cft
JOIN company ON company.id = cft.company_id
GROUP BY company.id
) AS DATA
GROUP BY DATA.company_id;
the tables look like the following (below). There is a relation between company.id and company_feature.company_id.
company table
| id | ref_set | size |
| -- | --- | --- |
| 1 | 0 | SMALL |
| 2 | 1 | LARGE |
company_feature table
| company_id | F1 | F2 |
| --- | --- | --- |
| 1 | 5 | 10 |
| 2 | 15 | 20 |
The query outputs the following data:
| company_id | feature_1 |
| --- | --- |
| 1 | -1.66 |
| 2 | -1.44 |
Yes, you just cross join them:
SELECT
DATA.company_id,
(
CASE
WHEN DATA.in_ref_set = 0 AND DATA.size = 'SMALL'
THEN
1 * ((LN(DATA.F1 + 1) - TOTALS.F1_mean) / TOTALS.F1_std_dev ) * 1
WHEN DATA.in_ref_set = 0 AND DATA.size = 'MEDIUM'
THEN
2 * ((LN(DATA.F1 + 1) - TOTALS.F1_mean) / TOTALS.F1_std_dev ) * 2
WHEN DATA.in_ref_set = 0 AND DATA.size = 'LARGE'
THEN
3 * ((LN(DATA.F1 + 1) - TOTALS.F1_mean) / TOTALS.F1_std_dev ) * 3
WHEN DATA.in_ref_set = 0 AND DATA.size = 'VERY_LARGE'
THEN
4 * ((LN(DATA.F1 + 1) - TOTALS.F1_mean) / TOTALS.F1_std_dev ) * 4
ELSE
5 * ((LN(DATA.F1 + 1) - TOTALS.F1_mean) / TOTALS.F1_std_dev )
END
) AS feature_1
FROM (
SELECT company.in_ref_set, company.size, cft.*
FROM company_feature_test cft
JOIN company ON company.id = cft.company_id
GROUP BY company.id
) AS DATA
CROSS JOIN (
SELECT
AVG(F1) AS F1_mean,
STDDEV(F1) AS F1_std_dev
FROM company_feature_test cft
) AS TOTALS
Note that there's no need to group by in the outer query; there will already only be one row per company.
Note that you still seem to be doing conditional aggregation incorrectly, if that is what you are trying to do; assuming there are multiple rows in cft for each company, you will be selecting an arbitrary F1 for each company. Default settings in newer versions of mysql will prohibit this.

SQL: Query adjacent nodes in a directed graph

I have a graph with nodes {A, B, C, D, ...} and a table which specifies the directed edges between them.
| node_1 | node_2 |
|-----------------|
| A | B |
| A | C |
| B | A |
| B | D |
| D | A |
We write A ~ B if there is an edge from A to B. So a row where node_1 = A and node_2 = B implies A ~ B. I distinguish between the following types of relations:
A = B if A ~ B and B ~ A
A > B if A ~ B and not B ~ A
A < B if B ~ A and not A ~ B
How can I retrieve all the nodes adjacent to a given node along with their type of relation? For example, a query for A on the above table should return
| node | type |
|------|------|
| B | = | (because A ~ B and B ~ A)
| C | > | (because A ~ C and not C ~ A)
| D | < | (because D ~ A and not A ~ D)
here is one way :
select node,
case when count(*) = 2 then '='
when max(ordertype) = 1 then '>'
when max(ordertype) = 2 then '<' end as type
from (select node2 node,
1 ordertype
from nodes
where node1 = 'A'
union all
select node1,
2
from nodes
where node2 = 'A') t
group by node
order by node
Hmmm . . . you can use conditional logic with aggregation:
select (case when node_1 = 'A' then node_2 else node_1 end) as other_node,
(case when count(*) = 2 then '='
when max(node_1) = 'A' then '>'
else '<'
end) as type
from nodes n
where 'A' in (node_1, node_2)
group by (case when node_1 = 'A' then node_2 else node_1 end);
Here is a db<>fiddle.
This seems like the simplest and probably the most performant solution.

SQL: How to find the row with a maximum number of a specific value

I need to find the row containing the most ones in this specific table.
the table looks like that and my output is shown just above the given table.
I am yet unfamiliar with sql so maybe it is easy to solve but I didn't get any solution so far.
Is there a way to say please search for a specific value and sum the found values up and the output should be given in an extra column?
looks pretty basic stuff ... hope this helps :
SELECT X.*,
CASE WHEN X.A=1 THEN 1 ELSE 0 END +
CASE WHEN X.B=1 THEN 1 ELSE 0 END +
CASE WHEN X.C=1 THEN 1 ELSE 0 END +
CASE WHEN X.D=1 THEN 1 ELSE 0 END +
CASE WHEN X.E=1 THEN 1 ELSE 0 END +
CASE WHEN X.F=1 THEN 1 ELSE 0 END AS SUM_ONES
FROM X;
Assuming your column data types are numeric, you can use this:
SELECT
CASE WHEN col1 = 1 THEN '*' ELSE '' END ||
CASE WHEN col2 = 1 THEN '*' ELSE '' END ||
...
AS RowValueSearchString
Then just use a LEN/CHAR_LENGTH function (depending on whatever DB you have) on RowValueSearchString to find the length of the string above. The concatenated string's length will give you the number of occurrences of the value you're looking for within the row.
You can use CASE OR IIF if you are on SQL Server 2012+ as:
CREATE TABLE X (
A INT,
B INT,
C INT,
D INT,
E INT,
F INT
);
INSERT INTO X VALUES
(1, 0, 0, 1, 0, 1),
(2, 0, 1, 2, 1, 0),
(1, 0, 1, 0, 1, 0);
SELECT X.*,
IIF(A = 1, A, 0) +
IIF(B = 1, B, 0) +
IIF(C = 1, C, 0) +
IIF(D = 1, D, 0) +
IIF(E = 1, E, 0) +
IIF(F = 1, F, 0) AS [Σ]
FROM X;
Results:
+---+---+---+---+---+---+---+
| A | B | C | D | E | F | Σ |
+---+---+---+---+---+---+---+
| 1 | 0 | 0 | 1 | 0 | 1 | 3 |
| 2 | 0 | 1 | 2 | 1 | 0 | 2 |
| 1 | 0 | 1 | 0 | 1 | 0 | 3 |
+---+---+---+---+---+---+---+

LEFT JOIN BETWEEN TWO TABLES

I have two tables X AND Y.i Have two coloumns in table X namely A and B and coloumn C in table Y.
Now i want to join X and Y using Left join With ON Condition
X.a=y.c or X.b=y.c. I want to get rows for 'c' coloumn in table Y with respective to rows for 'a 'coloumn in table X and 'c' cOLOUMN in table Y with respective to rows for B'coloumn in table X .
Result should be like :
-----------------------
X.a Y.C X.B Y.C
1 1 5 5
2 2 10 10
3 3 20 20
NULL NULL NULL NULL
You can simply do this
SELECT x.a, y1.c ac, x.b, y2.c bc
FROM x
LEFT JOIN y y1 ON x.a = y1.c
LEFT JOIN y y2 ON x.b = y2.c
Sample output:
| A | AC | B | BC |
|--------|--------|--------|--------|
| 1 | 1 | 5 | 5 |
| 2 | 2 | 10 | 10 |
| 3 | 3 | 20 | 20 |
| (null) | (null) | (null) | (null) |
Here is SQLFiddle demo
SELECT X.a, X.b, Y.c
FROM X LEFT JOIN Y
ON X.a = Y.c OR X.b = Y.c
Where's your problem ?
Is the problem not knowing sql syntax ? otherwise you're probably not framing your problem statement correctly
Based on your comment I'm going with the assumption that you want to know for which match is the value being retrieved and the modified query is :
SELECT X.a, X.b, Y.c,
CASE WHEN (X.a = Y.c AND X.b != Y.c) THEN 'a'
WHEN (X.a != Y.c AND X.b = Y.c) THEN 'b'
WHEN (X.a = Y.c AND X.b = Y.c) THEN 'ab' END AS 'FromColumn'
FROM X LEFT JOIN Y
ON X.a = Y.c OR X.b = Y.c

How do I fix this query to multiply a column value

I have this table
select * from points
+---------+------+------+
| NAME | Type | RANK |
+---------+------+------+
| A | H | 90 |
| A | M | 100 |
| A | H | N/A |
| A | H | N/A |
| A | H | N/A |
| B | H | 100 |
| B | M | 100 |
| B | L | 100 |
| C | H | 85 |
| C | M | 100 |
+---------+------+------+
I'm using this query
SELECT name,
CAST(
( -- only have H, or only have M, or only have L:
CASE WHEN `# of H` = 0 AND `# of M` = 0 THEN 100 * `# of active L` / `# of L`
WHEN `# of H` = 0 AND `# of L` = 0 THEN 100 * `# of active M` / `# of M`
WHEN `# of M` = 0 AND `# of L` = 0 THEN 100 * `# of active H` / `# of H`
-- only have H & M, or only have H & L, or only have M & L:
WHEN `# of H` = 0 THEN 60 * `# of active M` / `# of M` + 40 * `# of active L` / `# of L`
WHEN `# of M` = 0 THEN 90 * `# of active H` / `# of H` + 20 * `# of active L` / `# of L`
WHEN `# of L` = 0 THEN 80 * `# of active H` / `# of H` + 20 * `# of active M` / `# of M`
-- have all three:
ELSE 70 * `# of active H` / `# of H` + 20 * `# of active M` / `# of M` + 10 * `# of active L` / `# of L`
END
) AS SIGNED ) AS score
FROM ( SELECT name,
SUM(IF( type = 'H', 1, 0)) AS `# of H`,
SUM(IF(rank AND type = 'H', 1, 0)) AS `# of active H`,
SUM(IF( type = 'M', 1, 0)) AS `# of M`,
SUM(IF(rank AND type = 'M', 1, 0)) AS `# of active M`,
SUM(IF( type = 'L', 1, 0)) AS `# of L`,
SUM(IF(rank AND type = 'L', 1, 0)) AS `# of active L`
FROM points
GROUP BY name
) t
ORDER
BY name
;
I get this Output
+---------+-------+
| NAME | SCORE |
+---------+-------+
| A | 60 | <--[(2xH)=40 + (1xM)=20] =60
| B | 100 | <--[(1xH)=70 + (1xM)=20 + (1xL)=10] =100
| C | 100 | <--[(1xH)=80 + (1xM)=20] =100
+---------+-------+
I need this Desired output
+---------+-------+
| NAME | SCORE |
+---------+-------+
| A | 36 | <--[70/4=(17.5 per H) therefore (17.5)*(rank of that h: 90%)=15.75 + (M values, which equals 20/1 =20 Therefore: rank of that m:100% * 20 = 100) = 36 rounded
| B | 100 | <--[(1xH)=70 + (1xM)=20 + (1xL)=10] =100
| C | 88 | <--[(1xH)=80 + (1xM)=20] =100
+---------+-------+
Computations required:
Type can have only three values: {H, M, L};
When all values are present, they are graded as followed:
H=70 M=20 L=10
If an name has more than one kind of Type (H, M, or L) then points are distributed as followed:
H/(number of H) ; M/(number of M); L/(number of L)
-- Example: A has 4 H therefore 70 / 4 = 17.5 for each H
But some names have a complete set with out having all 'Types.
-- example : C has Type values: 'H&M` only
Now Type 'H' and 'M' have to equal 100 for C.
So when only 'H` and 'M' are present they are graded as followed:
H=80 M=20
Equally if another animal comes along with only two Type values M & L they will be graded as followed:
M=60 L=40
Equally if another animal comes along with only two Type values H & L they will be graded as followed:
H=90 L=10
And also
if only H is presnet H=100
if only M is presnet M=100
if only L is presnet L=100
This looks familiar. :-)
Your description is inconsistent in a number of places — for example, your "desired output" for A uses 70 and 20, even though no As have type L — but if you mean what I think you do, then the main change you need is to change SUM(IF(rank AND type = 'H', 1, 0)) AS `# of active H` to SUM(IF(type = 'H', rank / 100.0, 0)) AS `rank of H` (and likewise for M and L), and change all references to `# of active H` to refer to `rank of H` instead. This way each record will be included in proportion to its rank, rather than being an all-or-nothing thing.
You'll also want to use ROUND instead of CAST — or in addition to CAST — when converting your score to an integer.