SQL Server - Finding bitwise OR values using query - sql-server

I have a business requirement to search through a database table where one of the columns is a bitwise integer and remove the base values from a table.
For example, assume my table/resultset looks like this currently:
Value
-----
1
2
16
32
33
Notice that 33 is present, which is also 32 | 1. What I need to do is remove the 1 and 32 values to return this:
Value
-----
2
16
33
Obviously I could do this with looping constructs in SQL - or even in my business logic in C# - but I'm wondering whether this is at all possible using a query?

Here's a query that ought to work.
DELETE myTable WHERE myTable.Value in
(SELECT T1.Value
FROM myTable T1
CROSS JOIN myTable T2
WHERE T1.Value<>T2.Value AND T1.Value<T2.Value AND ((T1.Value | T2.VALUE)=T2.Value))

Try:
with cte(Value) as (
select 1 as Value
union all
select 2
union all
select 16
union all
select 32
union all
select 33
)
--select values to be removed
select x1.Value
from cte x1
inner join cte x2 on x1.Value <> x2.Value
inner join cte x3 on x1.Value <> x3.Value and x2.Value <> x3.Value
where x1.Value | x2.Value = x3.Value

Related

Strange SUM causing "Arithmetic overflow error converting expression to data type money"?

Firstly this seems to only happen when using a JOIN in the query, without joining, the SUM just works.
Suppose I have 2 tables TableA, TableB (references TableA via AId column),
TableB.Value has data type of money.
-- this throws the overflow exception
select sum(TableB.Value)
from TableA
join TableB on TableA.Id = TableB.AId
group by TableA.Id
As you can see, the input value for SUM is TableB.Value, so basically if we don't use JOIN, we can write it simply like this (just to test if overflowing happens):
select sum(TableB.Value)
from TableB
group by AId
I expected this has an overflow error as well but it works without any error.
So it's very strange this way.
I think this can be reproduced with dummy data somehow (but I don't have such data to upload here). I hope you could still guess or explain what is wrong here?
Please note that I need some explanation for this first, I do know one way to avoid the exception being thrown by casting the TableB.Value to decimal(19,4) first.
UPDATE
The TableB has a lot of rows with AId being null. The sum of TableB.Value grouped on that null will cause the overflow exception. But looks like when joining, all those null AIds are involved somehow?
So if filtering out all those null AIds, it works:
select sum(TableB.Value)
from TableA
join (select * from TableB
where AId is not null) v
on TableA.Id = v.AId
group by TableA.Id
The problem seems to be your misunderstanding of how JOINs and SUMs work.
Let's take the following 2 tables:
TableA
ID
I
1
12
2
13
TableB
ID
A_ID
I
1
1
17
2
1
12
3
2
7
4
2
19
5
3
1
Now take the following query:
SELECT SUM(I) AS SumI
FROM dbo.TableA;
This would result in the value 25: 12 + 13
Now let's take the following query, which you effectively have.
SELECT SUM(A.I) AS SumI
FROM dbo.TableA A;
JOIN abo.TableB B On A.ID = B.A_ID;
This would result in the value 63 not 25. This is because you have a many to one relationship. As a result the actual SUM would be 12 + 12 + 13 + 13 + 13 or (12 * 2) + (13 * 3).
This can be better seen if you remove the aggregation:
SELECT A.ID,
A.I
FROM dbo.TableA A;
JOIN abo.TableB B On A.ID = B.A_ID;
This will return the following:
ID
I
1
12
1
12
2
13
2
13
2
13
I suspect what you actually need is something like an EXISTS:
SELECT SUM(A.I)
FROM dbo.TableA A
WHERE EXISTS (SELECT 1
FROM dbo.TableB B
WHERE B.A_ID = A.ID);
This will return 25.

Get a count of all tables and Views in the database

I'm trying to write a query to get a count of all the tables and views and a sum of the two
Here is what i have so far:
Select
SCHEMA_NAME(schema_id) SchemaName,
type,
COUNT(*) TablesPerSchema,
COUNT(*) ViewsPerSchema,
'sum of tables and views' Total
From
Sys.objects
Where
type = 'U' or type = 'V'
Group By
SCHEMA_NAME(schema_id), type
Order By
Type, SchemaName
This works somewhat but I need to see the TablesPerSchema and ViewsPerSchema side by side. Right now it just showing Count(*) in each column.
Essentially, you are asking how to pivot your results so that per-type aggregates appear as columns. This can be done with the PIVOT operator:
select SchemaName,
ISNULL([U],0) as TablesPerSchema,
ISNULL([V],0) as ViewsPerSchema,
ISNULL([U],0) + ISNULL([V],0) As Total
From
(
select SCHEMA_NAME(schema_id) SchemaName,type,count(*) as TypeCount
from Sys.objects
Where type in ( 'U','V' )
group by SCHEMA_NAME(schema_id),type) T
PIVOT (
sum(TypeCount)
for [type] in ( [U],[V] )
) as pvt
The result will look like this:
SchemaName TablesPerSchema ViewsPerSchema Total
------------ --------------- -------------- -----------
dbo 46 117 163
GDS 0 3 3
IATA 3 10 13
Integration 2 4 6
Merchant 0 8 8
Portal 2 0 2
Reports 2 0 2
The PIVOT operator essentially means that for each type in the type list:
`for [type] in ( [U],[V] )`
the aggregate sum(TypeCount) will be calculated and placed in a new column with the same name as the type, ie V and U
use AdventureWorks2014
;with cte as
(
select
isnull(t.SchemaName, v.SchemaName) as SchemaName,
isnull(t.TablesPerSchema, 0) as TablesPerSchema,
isnull(v.ViewsPerSchema, 0) as ViewsPerSchema,
(isnull(t.TablesPerSchema, 0) + isnull(v.ViewsPerSchema, 0)) as 'Total'
from
(
Select
SCHEMA_NAME(schema_id) SchemaName,
type,
COUNT(*) TablesPerSchema
from
Sys.objects
Where
type = 'U'
Group By
SCHEMA_NAME(schema_id), type
) as t
full outer join
(
Select
SCHEMA_NAME(schema_id) SchemaName,
type,
COUNT(*) ViewsPerSchema
From
Sys.objects
Where
type = 'V'
Group By
SCHEMA_NAME(schema_id), type
) as v
on t.SchemaName = v.SchemaName
) select * from cte order by SchemaName
Result
SchemaName TablesPerSchema ViewsPerSchema Total
------------------------------- -------------- -----------
dbo 3 0 3
HumanResources 6 6 12
Person 13 2 15
Production 25 3 28
Purchasing 5 2 7
Sales 19 7 26
(6 row(s) affected)
Here is the logic
Select the tables from sys.objects.
Select the views from sys.objects.
Then full outer join the results of the two selects on schema name. The full outer join ensures that the if the schema does not have tables but has views or vice versa is still include in the final results.
Then use isnull() to get schema names from one of the result sets and to replace nulls with zeros.
Finally use Common Expression table to sort the results by schemaname.
In your question, you have included type in the select columns, however, for each row since you expect # of views and # of tables, having only one type column does not make sense, so I haven't kept it in my answer. Also the TablesPerSchema and ViewsPerSchema anyways indicate what type of object they are representing.

Whats the difference between UNION and CROSS JOIN?

I have been reading about this two possibilities but I'm not sure if I understood them properly.
So UNION makes new rows with the union of the two queries data:
Table1 Table2
------ ------
1 3
2 4
SELECT * FROM TABLE1
UNION
SELECT * FROM TABLE2
Column1
---------
1
2
3
4
...
And CROSS JOIN makes Cartesian product of both tables:
SELECT * FROM TABLE1
CROSS JOIN TABLE 2
Column1 | Column2
-----------------
1 | 3
2 | 3
1 | 4
2 | 4
Its that ok?
Thanks for all.
The UNION operator is used to combine the result-set of two or more SELECT statements.
The JOIN keyword is used in an SQL statement to query data from two or more tables, based on a relationship between certain columns in these tables.
If there is no relationship between the tables then it leads to cross join.
Others have already answered this question, but I just wanted to highlight that your example of the CROSS JOIN should return 4 and not 2 records.
Cross joins return every combination of records from the left of the join against the right.
Example Data
/* Table variables are a great way of sharing
* test data.
*/
DECLARE #T1 TABLE
(
Column11 INT
)
;
DECLARE #T2 TABLE
(
Column21 INT
)
;
INSERT INTO #T1
(
Column11
)
VALUES
(1),
(2)
;
INSERT INTO #T2
(
Column21
)
VALUES
(3),
(4)
;
UNION Query
/* UNION appends one recordset to the end of another,
* and then deduplicates the result.
*/
SELECT
*
FROM
#T1
UNION
SELECT
*
FROM
#T2
;
Returns
Column11
1
2
3
4
CROSS JOIN Query
/* CROSS JOIN returns every combination of table 1
* and table 2.
* The second recordset is appended to the right of the first.
*/
SELECT
*
FROM
#T1
CROSS JOIN #T2
;
Returns
Column11 Column21
1 3
2 3
1 4
2 4
Also important to note that Union will need exact same number of columns for both table while cross will not.
It is worth mentioning that unlike joins, UNION and CROSS-JOIN return all information about two tables and do not eliminate anything. But joins, inner and left/right joins, eliminate some part of the data which is not shared.

how to do a FOR EACH loop in T-Sql using join?

I have a table PRODUCT that is basically set up so there is an PRODUCTID, PRODUCTNAME... it looks sort of like this
PRODUCTID PRODUCTNAME
100 PNAME1
101 PNAME2
102 PNAME3
Now I have to insert a record into new table PRODUCTMAPPING for each row in the PRODUCT.
so my new table PRODUCTMAPPING should look like this
PRODUCTMAPPINGID PRODUCTID
1 100
1 101
1 102
2 100
2 101
2 102
3 100
and so on ....
I tried doing while but I need it using Join.
Can we acheive this using joins ?
Thanks in advance.
One way;
select
row_number() over(partition by a.PRODUCTID order by a.PRODUCTID) PRODUCTMAPPINGID,
a.PRODUCTID
from PRODUCT a, PRODUCT b
Using LOOP
The following example specifies that the JOIN operation in the query is performed by a LOOP join.
Select sp.Name,spqh.quota
FROM Sales.SalesPersonQuotaHistory AS spqh
INNER LOOP JOIN Sales.SalesPerson AS sp
ON spqh.SalesPersonID = sp.SalesPersonID
WHERE sp.SalesYTD > 2500000.00;
GO
Refer this MSDN link
INSERT
INTO dbo.PRODUCTMAPPING
(
PRODUCTMAPPINGID
,PRODUCTID
)
SELECT pmv.PRODUCTMAPPINGID
,p.PRODUCTID
FROM dbo.Product p
CROSS JOIN
(
SELECT pm.ProductMappingID
FROM dbo.ProductMappingValues pmv -- WHERE DO THESE COME FROM?
) pmv

SQL set operation with different number of columns in each set

Let say I have set 1:
1 30 60
2 45 90
3 120 240
4 30 60
5 20 40
and set 2
30 60
20 40
I would like to do some sort of union where I only keep rows 1,4,5 from set 1 because the latter 2 columns of set 1 can be found in set 2.
My problem is that set based operations insist on the same numnber of columns.
I've thought of concatenating the columns contents, but it feels dirty to me.
Is there a 'proper' way to accomplish this?
I'm on SQL Server 2008 R2
In the end, I would like to end up with
1 30 60
4 30 60
5 20 40
CLEARLY I need to go sleep as a simple join on 2 columns worked.... Thanks!
You are literally asking for
give me the rows in t1 where the 2 columns match in T2
So if the output is only rows 1, 4 and 5 from table 1 then it is a set based operation and can be done with EXISTS or INTERSECT or JOIN. For the "same number of column", then you simply set 2 conditions with an AND. This is evaluated per row
EXISTS is the most portable and compatible way and allows any column from table1
select id, val1, val2
from table1 t1
WHERE EXISTS (SELECT * FROM table2 t2
WHERE t1.val1 = t2.val1 AND t1.val2 = t2.val2)
INTERSECT requires the same columns in each clause and not all engines support this (SQL Server does since 2005+)
select val1, val2
from table1
INTERSECT
select val1, val2
from table2
With an INNER JOIN, if you have duplicate values for val1, val2 in table2 then you'll get more rows than expected. The internals of this usually makes it slower then EXISTS
select t1.id, t1.val1, t1.val2
from table1 t1
JOIN
table2 t2 ON t1.val1 = t2.val1 AND t1.val2 = t2.val2
Some RBDMS support IN on multiple columns: this isn't portable and SQL Server doesn't support it
Edit: some background
Relationally, it's a semi-join (One, Two).
SQL Server does it as a "left semi join"
INTERSECT and EXISTS in SQL Server usually give the same execution plan. The join type is a "left semi join" whereas INNER JOIN is a full "equi-join".
You could use union which, as opposed to union all, eliminates duplicates:
select val1, val2
from table1
union
select val1, val2
from table1
EDIT: Based on your edited question, you can exclude rows that match the second table using a not exists subquery:
select id, col1, col2
from table1 t1
where not exists
(
select *
from table2 t2
where t1.col1 = t2.col1
and t1.col2 = t2.col2
)
union all
select null, col1, col2
from table2
If you'd like to exclude rows from table2, omit union all and everything below it.

Resources