Get the "OR" result of all rows of a bit column - sql

I have a table like this:
**ID** | **read** | **edit** | **delete**|
1 true false false
2 false false true
3 true false true
4 true false false
I want to "OR" the rows and at last create a row that contain the OR result of them. is there any way to do it without for loop? what is the best way ? (row may be so many and i think for loop may reduce speed)

You could just cast the bits to integers and use MAX to get the biggest value;
SELECT MAX(CAST([read] AS INT)) [read],
MAX(CAST([edit] AS INT)) [edit],
MAX(CAST([delete] AS INT)) [delete]
FROM mytable;
An SQLfiddle to test with.

Try this:
select
cast(max(cast([read] as int)) as bit) as [overall_read],
cast(max(cast([edit] as int)) as bit) as [overall_edit],
cast(max(cast([delete] as int)) as bit) as [overall_delete]
from tbl
a or b is True when at least 1 of a or b is True, and False otherwise. So you can directly reduce this to getting the maximum value for each column, as #Joachim has also pointed out.

Related

calculate percentage/repartition of values with a sql query

I have the following table
type
color
value
A
white
true
B
black
false
c
yellow
true
d
red
true
f
green
false
and I want to calculate with a sql query the percentage of rows having value equal to true , here for example we have 3 trues over a total of 5 lines which makes a percentage of 60% of types having a value equal to true , any idea how to fix this please ?
Do you just want a single value to be returned?
Depending on which RDBMS you're using boolean values are handled differently, but the basic structure should be similar to...
SELECT
SUM(CASE WHEN value = true THEN 1 ELSE 0 END) * 1.0 / COUNT(*)
FROM
yourTable
You can use avg():
select avg(case when value = 'true' then 1.0 else 0 end) as ratio
from t;
This returns the ratio, between 0 and 1. If you want a percentage between 0 and 100, then use 100.0 instead of 1.0.

Need to compare the cell values of same column of a table based on another column value in SQL

I need to compare the cells of a column of a table based on the value of another column value in sql.
Id A B
1 Ram 50
2 Ram 50
3 Siva 123
4 Siva 25
5 Rose 75
6 Rose 75
7 Siva 123
I have the above table, i need to check whether Ram in Column A has same value in column B, if not i should return false.
In the above case it should return false as Siva in(Column A) has different values in Column B.
I don't know how to do this. Kindly help on the same.
Result Expected
Return "False", as there is value mismatch for Siva
Here is one trick
select A,
case when min(B)=max(B) then 'True' else 'False' end as Flag
From yourtable
Group by A
or If you want to display the flag column for every row then
select A,
case when min(B)over(partition by A)=max(B)over(partition by A) then 'True' else 'False' end as Flag
From yourtable
Update : If you want to display False if at least one mismatch is present then
SELECT CASE
WHEN EXISTS(SELECT 1
FROM yourtable
GROUP BY A
HAVING Min(B) <> Max(B)) THEN 'False'
ELSE 'True'
END

unusual sql server query result

Let's say I have a table called nameAge:
ID Name Age
1 X 12
2 Y 12
3 null null
4 Z 12
and when I run a query like:
select * from nameAge where Age <> 12
it returns me an empty result set while I have row with id 3 where age is different than null?
Using Sql Server 2008 R2.
Any ideas?
Edit: Possibility to be duplicate with suggested answer may be at one point but does not cover at all and it shows how to use null values when compared with null but what I wanted to ask was about the result set which includes null values
This is the intended behavior. You cannot compare NULL values using = or <>. You have to use IS NULL or IS NOT NULL.
If you want NULL values only use IS NULL:
select * from nameAge where age IS NULL
If you want NULL values with age <> 12 values, use:
select * from nameAge where age <> 12 OR age IS NULL
The expression
WHERE NULL <> 12
does not return TRUE or FALSE, but actually returns UNKNOWN. This means that the third record in your table will not be returned by your query.
As #ughai mentioned, you should use IS NULL instead to query that record:
SELECT * FROM nameAge WHERE age IS NULL
Have a look at the Microsoft SQL Server documentation for more information.
When you are dealing with NULLs you should be always careful because of 3 valued logic used in Sql Server(when a predicate can be evaluated to TRUE, FALSE or UNKNOWN). Now here is a classic select statement where many newcomers make a mistake, suggesting that the statement would return all rows where Age <> 12 including NULLs.
But if you know the easy fact that comparing NULL to any value, even to NULL itself will evaluate to UNKNOWN it is getting more clear what is going on. WHERE clause will return ONLY those rows where predicate is evaluated to TRUE. Rows where predicate evaluates to FALSE or UNKNOWN will be filtered out from resultset.
Now let's see what is going on behind the scene. You have 4 rows:
ID Name Age
1 X 12
2 Y 12
3 null null
4 Z 12
and the predicate is:
where Age <> 12
When you evaluate this predicate for each row you get:
ID Name Age Evaluation result
1 X 12 FALSE --(because 12 <> 12 is FALSE)
2 Y 12 FALSE --(because 12 <> 12 is FALSE)
3 null null UNKNOWN --(because NULL <> 12 is UNKNOWN)
4 Z 12 FALSE --(because 12 <> 12 is FALSE)
Now remember that WHERE clause will return only rows where predicate evaluates to TRUE and it is clear that you will not get any result because no row evaluates to TRUE.

Sum statement counts everything, or northing

I am almost finished with my project, but i still have one issue left.
I need to create a summary with an sql code. The code is like this:
"SELECT SUM(prices of a column), select others FROM blablabla WHERE condintion 1 is true OR condition 2 is true OR condition 3 is true GROUP BY blablabla;"
The problem is, is that i can't use the above because of the OR. Whenever i use OR, it see's that condintion 1 for example is true, so he will ignore the rest of the conditions, but i need them to to see if they are true. The problem with using a "AND" instead of an "OR" causes to set the result to nothing because all three can't always be true.
So the bottomline is, My query needs to count some fields in a column where a field meets a condition. I use multiple conditions because there are diffrent kinds of products, but i somehow can't use the conditions al togheter because the statement counts everything whever one condition is met, or counts nothing because they can't always be true all three of them.
how do i fix this?
thanks
SELECT SUM(prices column) as Total
FROM yourTable
WHERE condition1 is true
GROUP BY columnBLabla
UNION ALL
SELECT SUM(prices column)
FROM yourTable
WHERE condition2 is true
GROUP BY columnBLabla
UNION ALL
SELECT SUM(prices column)
FROM yourTable
WHERE condition3 is true
GROUP BY columnBLabla
Result
Total
100 -- total price when condition 1 is true
230 -- total price when condition2 is true
900 -- total price when condition 3 is true
I'm not sure if I have completely understand the question, I think this is what you are looking for
SELECT SUM(prices of a column)
FROM blablabla
WHERE
(condintion 1 is true OR condition 2 is true)
AND
(condintion 1 is true OR condition 3 is true)
AND
(condintion 2 is true OR condition 3 is true)
GROUP BY blablabla;
OR may be
SELECT SUM(prices of a column)
FROM blablabla
WHERE
(condintion 1 is true AND condition 2 is true)
OR
(condintion 1 is true AND condition 3 is true)
OR
(condintion 2 is true AND condition 3 is true)
GROUP BY blablabla;
I may be misunderstanding but, could you use a case statement? You could put each of the conditions in its own "When X is true A" statement. Then by varying/or not varying the A you could make category to summarize on.
How about this?
SELECT
SUM(CASE WHEN condition1 THEN prices_of_a_column ELSE 0 END) AS prices1,
SUM(CASE WHEN condition2 THEN prices_of_a_column ELSE 0 END) AS prices2,
SUM(CASE WHEN condition3 THEN prices_of_a_column ELSE 0 END) AS prices3
FROM blabla
GROUP BY blabla

Return true if all column values are true

Is there a faster way in PostgreSQL to essentially do an if on several rows?
Say I have a table
ticket | row | archived
1 | 1 | true
1 | 2 | true
1 | 3 | true
2 | 1 | false
2 | 2 | true
Is there any way I could do an if statement across down the column where ticket = ?
So that where ticket = 1 would be true because
true && true && true = true
and where ticket = 2 would be false because
false && true = false
Or should I just stick with
SELECT ( (SELECT COUNT(*) FROM table WHERE ticket = 1)
= (SELECT COUNT(*) FROM table WHERE ticket = 1 AND archived = true) )
Aggregate function bool_and()
Simple, short, clear:
SELECT bool_and(archived)
FROM tbl
WHERE ticket = 1;
The manual:
true if all input values are true, otherwise false
Subquery expression EXISTS
Assuming archived is defined NOT NULL. Faster, but you have to additionally check whether any rows with ticket = 1 exist at all, or you'll get incorrect results for non-existing tickets:
SELECT EXISTS (SELECT FROM tbl WHERE ticket=1)
AND NOT
EXISTS (SELECT FROM tbl WHERE ticket=1 AND NOT archived);
Indices
Both forms can use an index like:
CREATE INDEX tbl_ticket_idx ON tbl (ticket);
.. which makes both fast, but the EXISTS query faster, because this form can stop to scan as soon as the first matching row is found. Hardly matters for only few rows per ticket, but matters for many.
To make use of index-only scans you need a multi-column index of the form:
CREATE INDEX tbl_ticket_archived_idx ON tbl (ticket, archived);
This one is better in most cases and any version of PostgreSQL. Due to data alignment, adding a boolean to the integer in the index will not make the index grow at all. Added benefit for hardly any cost.
Update: this changes in Postgres 13 with index deduplication. See:
Is a composite index also good for queries on the first field?
However, indexed columns prevent HOT (Heap Only Tuple) updates. Say, an UPDATE changes only the column archived. If the column isn't used by any index (in any way), the row can be HOT updated. Else, this shortcut cannot be taken. More on HOT updates:
Redundant data in update statements
It all depends on your actual workload.
How about something like:
select not exists (select 1 from table where ticket=1 and not archived)
I think this might be advantageous over comparing the counts, as a count may or may not use an index and really all you need to know is if any FALSE rows exist for that ticket. I think just creating a partial index on ticket could be incredibly fast.
SQL Fiddle
select not false = any (
select archived
from foo
where ticket = 1
)
SQL Fiddle