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.
Related
I have a question about the Any-Operator.
On Technet it says
For example, the following query finds customers located in a territory not covered by any sales persons.
Use AdventureWorks2008R2;
GO
SELECT
CustomerID
FROM
Sales.Customer
WHERE
TerritoryID <> ANY
(
SELECT
TerritoryID
FROM
Sales.SalesPerson
);
Further
The results include all customers, except those whose sales territories are NULL, because every territory that is assigned to a customer is covered by a sales person. The inner query finds all the sales territories covered by sales persons, and then, for each territory, the outer query finds the customers who are not in one.
But that query returns all customers.
I updated a customers TerritoryID to a value that no sales.person has, but still that query returns all customers, instead of that one I expected ..
Am I missing something ?
Might it be that that article on technet is simply wrong ?
https://technet.microsoft.com/de-de/library/ms187074(v=sql.105).aspx (german)
There is one customer with TerritoryID = 13
Inner query result (SELECT TerritoryID FROM Sales.SalesPerson) :
4
2
4
3
6
5
1
4
6
1
1
6
9
1
8
10
7
And in table Sales.Customer is a row with CustomerID = 13, which is the one not covered by a sales-person..
create table #t1
(
id int
)
insert into #t1
values(1),(2),(3)
As you can see,T1 has three values
now lets see,how Any Works
When 'is Equal to ' is used with any ,it works like IN
select * from #t1 where id=
any(select 0)--no result
when Any is used with > or <> ,Any means get me all the values which are greater than minimum value
select * from #t1 where id<>
any(select 1)--2,3
select * from #t1 where id<>
any(select 0)--1,2,3
If your subquery returns one value,the outer query will try to get values which are greater than inner query
<> ANY means any Sales.Customer with a TerritoryID that is Greater Than or Less Than any of the TerritoryID's in the Sales.SalesPerson
so TerritoryID = 13 is greater than all or your examples (4 2 4 3 6 5 1 4 6 1 1 6 9 1 8 10 7), so it's included.
<> ALL is the equivalent of NOT IN so that is what you're confusing <> ANY with
Look at <> ANY as, if there are any records in the set that are not equal to the quailifier, then include it.
The following query has the same result:
SELECT CustomerID FROM Sales.Customer
WHERE TerritoryID NOT IN (SELECT TerritoryID FROM Sales.SalesPerson)
I want to delete the duplicate(same from and same to values) tuples from a table but need to keep the tuple with minimum object id(object id is pk).
So here are columns:
from | to | time | distance | object_id
I can see the correct number of tuples that will be deleted by executing
select [from],[to],count(*)
FROM table
where [object_id] NOT IN(
SELECT min([object_id])
FROM table
group by [from],[to]
having count(*) > 1)
group by [from],[to]
having count(*) > 1
but I want to first see the object_id's which are counted on the SQL above.
You could try with this (untested)...
;WITH temp AS (
SELECT [from_id], [to_id], [object_id] = min([object_id])
FROM table
group by [from_id],[to_id]
having count(*) > 1)
SELECT
t2.[from_id],
t2.[to_id],
t.[object_id]
FROM
table t
join temp t2
on t2.[from_id] = t.[from_id]
AND t2.[to_id] = t.[to_id]
AND t2.[object_id] != t.[object_id]
EDIT:
CTE temp will yield all distinct from/to groupings with min object_id, one you would like to keep.
SELECT [from_id], [to_id], [object_id] = min([object_id])
FROM table
group by [from_id],[to_id]
having count(*) > 1
There are other pairs you would like to remove, and these are same from/to pairs, but with different object_id. Last select should output those records exactly.
I have two tables
table-a
id name
100 asd
101 ass
102 gdd
103 hgf
104 cvd
105 erf
table-b
id filter
100 red
101 blue
100 green
100 yellow
102 black
102 red
103 dark
Table-a is the master table and that have all the id's.but Table two is the one which has 'filter' data.
from these two table I want to find out all those 'id's which does not have minimum 2 filters.
note that table-b does not have all the itemnumbers in table-a, and i want all that itemnumber irrespective of if that is in table-a or table-b.I have tried inner joining these two tables and getting data out but nothing worked.
Select A.ID, A.Name, count(*)
from tableA A
LEFT JOIN tableB B on A.ID = B.ID
Group By A.ID, A.name
having count(*) <= 1
LEFT JOIN gives all records from A and only those in B which match.
The group by ID and name let us count the number of filters found in
each
The having says give me any items with a count less than or
equal to 1. (or less than the minimum 2)
Thus results would be.
101 ass 1
103 hgf 1
104 cvd 0
105 erf 0
select
*
from
table-a a
left join (
select id, count(id) as c from table-b group by id
) v on a.id = v.id
where isnull(v.id, 0) < 2
I think this would work in SQL Server (tested in SQLite and usually the two are fairly compatible when it comes to inline view syntax). But syntax issues aside, inline views can make working with sets easier to visualize.
select TA.id, name
from TA
inner join
(
select id from TA
where not exists (select id from TB where TA.id = TB.id)
UNION
select id from TB
group by id having count(filter) < 2
) as FOO
on TA.id = FOO.id
The default behavior of UNION is to remove duplicates.
The first UNIONed set consists of the ids from table A that have no filter (no counterpart in the filters table B).
The second UNIONed set consists of the ids from the filters table, table B, that have only 1 filter.
We inner join those unioned sets back to Table A to get the entity Name.
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
I'm trying to extract some data from a third party system which uses an SQL Server database. The DB structure looks something like this:
Order
OrderID OrderNumber
1 OX101
2 OX102
OrderItem
OrderItemID OrderID OptionCodes
1 1 12,14,15
2 1 14
3 2 15
Option
OptionID Description
12 Batteries
14 Gift wrap
15 Case
[etc.]
What I want is one row per order item that includes a concatenated field with each option description. So something like this:
OrderItemID OrderNumber Options
1 OX101 Batteries\nGift Wrap\nCase
2 OX101 Gift Wrap
3 OX102 Case
Of course this is complicated by the fact that the options are a comma separated string field instead of a proper lookup table. So I need to split this up by comma in order to join in the options table, and then concat the result back into one field.
At first I tried creating a function which splits out the option data by comma and returns this as a table. Although I was able to join the result of this function with the options table, I wasn't able to pass the OptionCodes column to the function in the join, as it only seemed to work with declared variables or hard-coded values.
Can someone point me in the right direction?
I would use a splitting function (here's an example) to get individual values and keep them in a CTE. Then you can join the CTE to your table called "Option".
SELECT * INTO #Order
FROM (
SELECT 1 OrderID, 'OX101' OrderNumber UNION SELECT 2, 'OX102'
) X;
SELECT * INTO #OrderItem
FROM (
SELECT 1 OrderItemID, 1 OrderID, '12,14,15' OptionCodes
UNION
SELECT 2, 1, '14'
UNION
SELECT 3, 2, '15'
) X;
SELECT * INTO #Option
FROM (
SELECT 12 OptionID, 'Batteries' Description
UNION
SELECT 14, 'Gift Wrap'
UNION
SELECT 15, 'Case'
) X;
WITH N AS (
SELECT I.OrderID, I.OrderItemID, X.items OptionCode
FROM #OrderItem I CROSS APPLY dbo.Split(OptionCodes, ',') X
)
SELECT Q.OrderItemID, Q.OrderNumber,
CONVERT(NVarChar(1000), (
SELECT T.Description + ','
FROM N INNER JOIN #Option T ON N.OptionCode = T.OptionID
WHERE N.OrderItemID = Q.OrderItemID
FOR XML PATH(''))
) Options
FROM (
SELECT N.OrderItemID, O.OrderNumber
FROM #Order O INNER JOIN N ON O.OrderID = N.OrderID
GROUP BY N.OrderItemID, O.OrderNumber) Q
DROP TABLE #Order;
DROP TABLE #OrderItem;
DROP TABLE #Option;