Use Sum on extra aggregation and Make Total - sql-server

I want to create an indexed View.
I have this query:
SELECT srvmn.BBC_ID AS Inventory,
srvInv.ObjectID,
srv.State,
SUM( IIF(srvInv.Direction = srvInv.ReverseBroken, 1, 0)) AS Broken,
SUM(IIF(srvInv.Direction = 0, 1, -1)) AS Sum,
COUNT_BIG(*) AS CountLines
FROM table1 srvmn
JOIN table2 srv
ON srv.ServiceManID = srvmn.ID
JOIN table3 srvInv
ON srv.ID = srvInv.ServiceID
WHERE srv.State > 321
AND srv.State <> 123
GROUP BY srvInv.ObjectID,
srv.State,
srvInv.Direction,
srvInv.ReverseBroken,
srvmn.BBC_ID
ORDER BY srvInv.ObjectID
So, the Sum is not working properly also I fix it with this approach:
SELECT A.Inventory,
A.ObjectID,
A.State,
A.Broken,
SUM(A.Sum) AS Sum
FROM
(
SELECT srvmn.BBC_ID AS Inventory,
srvInv.ObjectID,
srv.State,
IIF(srvInv.Direction = srvInv.ReverseBroken, 1, 0) AS Broken,
SUM(IIF(srvInv.Direction = 0, 1, -1)) AS Sum,
COUNT_BIG(*) AS CountLines
FROM table1 srvmn
JOIN table2 srv
ON srv.ServiceManID = srvmn.ID
JOIN table3 srvInv
ON srv.ID = srvInv.ServiceID
WHERE srv.State > 321
AND srv.State <> 123
GROUP BY srvInv.ObjectID,
srv.State,
srvInv.Direction,
srvInv.ReverseBroken,
srvmn.BBC_ID
) AS A
GROUP BY A.Inventory,
A.ObjectID,
A.State,
A.Broken;
Result is OK, but Derived Tables are not allowed in Indexed Views.
I try to using "Over Partition" in Sum, but the result is not OK.
How I can fix this issue?
Correct Result :
Inventory ObjectID State Broken Sum
------------------------------------------------
NULL 2 500 0 -1
NULL 3 320 1 1
NULL 3 500 0 2
NULL 3 600 0 1
NULL 18 600 0 -1
NULL 20 600 0 -1
1162 20 600 0 1
NULL 24 600 0 1
NULL 26 310 0 -3
NULL 26 320 0 -1
NULL 26 600 0 7
442 26 500 0 8
442 26 500 1 1
442 26 600 0 -5
1162 26 600 0 0
NULL 27 500 0 4
NULL 27 600 0 2
1162 27 600 0 1
1162 28 600 0 3
Not Ok Result:
Inventory ObjectID State Broken Sum CountLines
-------------------------------------------------------------
NULL 2 500 0 -1 1
NULL 3 500 0 2 2
NULL 3 600 0 1 1
NULL 18 600 0 -1 1
1162 20 600 0 3 3
1162 20 600 0 -2 2
NULL 20 600 0 1 1
NULL 20 600 0 -2 2
NULL 24 600 0 -1 1
NULL 24 600 0 2 2
442 26 600 0 -7 7
NULL 26 600 0 -18 18
1162 26 600 0 1 1
NULL 26 600 0 25 25
442 26 500 1 1 1
442 26 600 0 2 2
1162 26 600 0 -1 1
442 26 500 0 8 8
NULL 27 600 0 -3 3
1162 27 600 0 1 1

Please try it :
SELECT
srvmn.BBC_ID AS Inventory,
srvInv.ObjectID,
srv.State,
SUM(IIF(srvInv.Direction = srvInv.ReverseBroken, 1, 0)) AS Broken,
SUM(IIF(srvInv.Direction = 0, 1, -1)) AS Sum
FROM table1 srvmn
JOIN table2 srv ON srv.ServiceManID = srvmn.ID
JOIN table3 srvInv ON srv.ID = srvInv.ServiceID
WHERE srv.State > 321 AND srv.State <> 123
GROUP BY
srvInv.ObjectID,
srv.State,
srvInv.ReverseBroken,
srvmn.BBC_ID

You should not use Field "srvInv.Direction" in "Group By"

Related

Combine a column while grouping on another column with similar values

I have been working on a SQL Server stored procedure to find a solution illustrated in the results table below. I am close in my solution however I get multiple results on a column I would like to have grouped altogether.
DECLARE #fiscal_year AS INT
SET #fiscal_year = '2016'
SELECT
[ActionDate] AS [PPDate],
SUM([GAL].[GCount]) AS [GCount],
SUM([GAL].[LCount]) AS [LCount],
CONCAT(SUM([GAL].[GCount]), ' Gain(s): (', [GAL].[GComments], '); ', SUM([GAL].
[LCount]), ' Loss(es): (', [GAL].[LComments], ')') AS [Details]
FROM
[dbo].[TableA] [GAL]
GROUP BY
[GAL].[ActionDate], [GAL].[GainComments], [Gal].[LossComments]
I have a table as follows.
Table A:
ID ActionDate GCount GainRID GComments LCount LossRID LComments
1 2013-06-04 1 35 John 0 -1 NULL
2 2013-06-04 2 35 M & R 0 -1 NULL
3 2014-01-10 1 60 Paul 0 -1 NULL
4 2014-01-10 1 60 Mona 0 -1 NULL
5 2013-10-05 3 58 Tim 0 -1 NULL
6 2013-10-05 2 58 Ruby 0 -1 NULL
7 2013-10-05 0 -1 NULL 2 50 Jude & Mo
8 2013-10-05 0 -1 NULL 1 50 Frank
9 2013-10-05 0 -1 NULL 1 50 Linda
10 2014-01-10 0 -1 NULL 1 70 Eliz
11 2014-01-10 0 -1 NULL 1 70 Georgina
12 2014-01-10 0 -1 NULL 1 70 Christina
13 2013-10-05 0 -1 NULL 2 64 Joan & Mike
14 2013-10-05 0 -1 NULL 1 64 Mitch
...and I would like to have it grouped by Action Date, using the SUM() function on the GainCount and LossCount fields. The Details field is combined by
GainReasonID, LossReasonID, Gain and Loss Comments such that the table ends up like this.
Results
PPDate GCount LCount Details
2013-06-04 2 0 "(2) Gains: 2(35) -- John, M & R
(0) Losses: "
2013-10-05 2 3 "(2) Gains: 2(58) -- Tim, Ruby
(3) Losses: 3(50) -- Jude & Mo, Frank, Linda ,
2(64) -- Joan & Mike, Mitch"
2014-01-10 2 3 "(2) Gains: 2(60) -- Paul, Mona
(3) Losses: 3(70) -- Eliz, Georgina, Christina"

SQL Pivot Table - Subqueries

I have a program that is logging the time a user spends on certain aspects, some are identified as specific "time". I'm struggling to get multiple lines of Grouped query results into a single line for each month as a "summary".
My current query:
SELECT
TotalMins = SUM(Minutes)
,DateMonth = MONTH(Date)
,ID1
,PC
FROM User_Time_Log
WHERE
(UserID = 1)
AND (YEAR(Date) = 2018)
GROUP BY
MONTH(Date)
,ID1
,PC1
Current results:
TotalMins DateMonth ID1 PC1
192 1 0 0
306 1 0 100
113 2 0 0
365 2 0 100
14 2 1 0
3 2 1 100
75 3 0 0
253 3 0 100
3 3 1 0
300 4 0 0
233 4 0 100
10 4 1 0
23 4 1 100
438 5 0 0
134 5 0 100
19 5 1 0
49 5 1 100
0 9 1 0
11 10 0 0
21 10 0 60
167 10 1 100
What I would like to do from this point is to create a table showing all 12 months, regardless of whether there is information within that month or not, and show the relative information within each row for that month. for example:
DateMonth NonID1 TimeID1 TimePC1 (Round((PC1/100)*TotalMins)) TimePC1ID1
1 192 0 306 0
2 113 14 365 3
3 75 3 253 0
4 300 10 233 23
5 438 19 134 49
6 0 0 0 0
7 0 0 0 0
8 0 0 0 0
9 0 0 0 0
10 11 0 13 167
11 0 0 0 0
12 0 0 0 0
What's the most efficient way to do this?
Note: I have also created a table to give me 1-12 as rows that I can use to give me the months that I need to use, where information is not within the user_time_log.
Here's a simple way to do what you're looking for:
First, create your table of month values. I made a simple temp table with a single column.
CREATE TABLE #Dates (MonthNum INT)
INSERT INTO #Dates
(
MonthNum
)
VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
Next, you can put your existing query into a CTE, then LEFT JOIN to your table of months. You'll want to put your columns into a SUM'd CASE statement, like so:
;WITH Aggregation AS
(
SELECT
TotalMins = SUM(Minutes)
,DateMonth = MONTH(Date)
,ID1
,PC1
FROM #User_Time_Log
WHERE
(UserID = 1)
AND (YEAR(Date) = 2018)
GROUP BY
MONTH(Date)
,ID1
,PC1
)
SELECT
d.MonthNum
,NonID1 = SUM(CASE WHEN ID1 = 0 THEN TotalMins ELSE 0 END)
,TimeID1 = SUM(CASE WHEN ID1 = 1 THEN TotalMins ELSE 0 END)
,TimePC1 = SUM(CASE WHEN ID1 = 0 THEN ROUND((PC1/100)*TotalMins,0) ELSE 0 END)
,TimePC1ID1 = SUM(CASE WHEN ID1 = 1 THEN ROUND((PC1/100)*TotalMins,0) ELSE 0 END)
FROM #Dates d
LEFT JOIN Aggregation a ON d.MonthNum = a.DateMonth
GROUP BY d.MonthNum
Output would then look like this:
MonthNum NonID1 TimeID1 TimePC1 TimePC1ID1
1 498 0 306 0
2 478 17 365 3
3 328 3 253 0
4 533 33 233 23
5 572 68 134 49
6 0 0 0 0
7 0 0 0 0
8 0 0 0 0
9 0 0 0 0
10 32 167 0 167
11 0 0 0 0
12 0 0 0 0
EDIT:
The ROUND() function call can be changed slightly to accomodate your need for decimal results. The first parameter of ROUND() is the expression you want to round, and the second is the number of decimal places to round to. Positive numbers indicate the number of places to the right of the decimal to round to. Negative numbers indicate the number of places to the left of the decimal to round to. So if you set it to 2, you'll get an answer rounded to the nearest hundredth.
But there's one more tweak we need. PC1 and TotalMins are both assumed to be INTs in my answer. So we have to give the SQL engine a little help so that it calculates the answer as a DECIMAL. By CAST()ing the INTs to DECIMALs, SQL will perform the arithmetic op as decimal math instead of integer math. You'd just have to change TimePC1 and TimePC1ID1 like so:
,TimePC1 = SUM(CASE WHEN ID1 = 0 THEN ROUND((CAST(PC1 AS DECIMAL)/100)*CAST(TotalMins AS DECIMAL),2) ELSE 0 END)
,TimePC1ID1 = SUM(CASE WHEN ID1 = 1 THEN ROUND((CAST(PC1 AS DECIMAL)/100)*CAST(TotalMins AS DECIMAL),2) ELSE 0 END)
Then the output looks like this:
MonthNum NonID1 TimeID1 TimePC1 TimePC1ID1
1 498 0 306.000000 0.000000
2 478 17 365.000000 3.000000
3 328 3 253.000000 0.000000
4 533 33 233.000000 23.000000
5 572 68 134.000000 49.000000
6 0 0 0.000000 0.000000
7 0 0 0.000000 0.000000
8 0 0 0.000000 0.000000
9 0 0 0.000000 0.000000
10 32 167 12.600000 167.000000
11 0 0 0.000000 0.000000
12 0 0 0.000000 0.000000

how to find records which has some specific values

i have one log table in that i can check how many records inserted in which table.
i want to find that in which device has 0 records inserted from complete logs.
sample data
Id DeviceID Success RecordInserted ErrorMessage LogDate
1 0000ACFFFE4D48 1 395 NULL 2018-05-11 12:54:55.713
2 0000ACFFFE4E6A 1 492 NULL 2018-05-11 12:55:10.277
3 0000ACFFFE51D9 1 247 NULL 2018-05-11 12:55:17.790
4 0000ACFFFE5585 1 399 NULL 2018-05-11 12:55:28.267
5 0000ACFFFE5B03 1 493 NULL 2018-05-11 12:55:44.313
6 0000ACFFFE56E3 1 456 NULL 2018-05-11 12:56:00.743
7 0000ACFFFE1183 1 410 NULL 2018-05-11 12:56:09.817
8 0000ACFFFE2693 1 333 NULL 2018-05-11 12:56:24.613
9 0000ACFFFE4454 1 456 NULL 2018-05-11 12:56:36.867
10 0000ACFFFE7223 1 10056 NULL 2018-05-11 13:03:04.410
11 0000ACFFFE1CBB 1 10046 NULL 2018-05-11 13:06:03.860
12 0000ACFFFE2F81 1 0 NULL 2018-05-11 13:06:06.567
13 0000ACFFFE6F29 1 0 NULL 2018-05-11 13:06:08.307
14 0000ACFFFE0B8D 1 10078 NULL 2018-05-11 13:10:28.020
15 0000ACFFFE4DF2 1 409 NULL 2018-05-11 13:10:39.950
16 0000ACFFFE4D48 1 0 NULL 2018-05-11 13:16:32.027
17 0000ACFFFE4E6A 1 1 NULL 2018-05-11 13:16:38.640
18 0000ACFFFE51D9 1 1 NULL 2018-05-11 13:16:41.997
19 0000ACFFFE5585 1 1 NULL 2018-05-11 13:16:49.473
20 0000ACFFFE5B03 1 1 NULL 2018-05-11 13:16:56.797
21 0000ACFFFE56E3 1 1 NULL 2018-05-11 13:17:03.703
22 0000ACFFFE1183 1 0 NULL 2018-05-11 13:17:10.283
23 0000ACFFFE2693 1 1 NULL 2018-05-11 13:17:14.830
24 0000ACFFFE4454 1 0 NULL 2018-05-11 13:17:21.880
25 0000ACFFFE7223 1 64 NULL 2018-05-11 14:06:32.153
26 0000ACFFFE1CBB 1 64 NULL 2018-05-11 14:09:26.907
27 0000ACFFFE2F81 1 0 NULL 2018-05-11 14:09:28.743
28 0000ACFFFE6F29 1 0 NULL 2018-05-11 14:09:30.667
29 0000ACFFFE0B8D 1 64 NULL 2018-05-11 14:11:42.227
30 0000ACFFFE4DF2 1 3 NULL 2018-05-11 14:11:48.857
Expected output
0000ACFFFE6F290B
0000ACFFFE2F818D
This 2 deviceid have 0 recordinserted
sql query
select deviceid from logs where recordinserted !=0 and deviceid in (select deviceid from logs where recordinserted= '0')
error
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Are you looking for devices with zero entries? Or devices whose entries total 0 RecordsInserted? I do not see your expected output Ids in the list and this Id '0000ACFFFE2F81' has two entries both with 0 Records Inserted.
For DeviceIds that are not listed, DeviceId needs to be a foreign key to another table, and you can find those that are not in the logs table with this query:
SELECT Id FROM DeviceTable
EXCEPT
SELECT DeviceId FROM Logs
To get those that have a sum total of 0 records in the Logs Table use this query:
SELECT DeviceId
,SUM(RecordsInserted)
FROM Logs
GROUP BY DeviceId
Having SUM(RecordsInserted) = 0
select deviceid from logs where recordinserted = 0
You can use the where clause like this when recordinserted column is integer type.
select deviceid
from logs
group by deviceid
having max(recordinserted) = 0 -- no row greater zero exists

SQL query to get Groups and sub groups hierarchy

Account table
ac_id ac_name st_id
----------- ------------- -----------
1 LIABILITES 1
2 ASSET 1
3 REVENUE 1
4 EXPENSES 1
5 EQUITY 1
Groups table
grp_id grp_name ac_no grp_of st_id type_ cmp_id
----------- ------------------- ---------- -------- --------- --------- --------
1 Capital Account 1 0 1 0 0
2 Current Liability 1 0 1 0 0
3 Loan Liability 1 0 1 0 0
4 Suspense A/C 1 0 1 0 0
5 Current Assets 2 0 1 0 0
6 Fixed Assests 2 0 1 0 0
7 Investment 2 0 1 0 0
8 Misc. Expenses 2 0 1 0 0
9 Direct Income 3 0 1 0 0
10 Indirect Income 3 0 1 0 0
11 Sale Account 3 0 1 0 0
12 Direct Expense 4 0 1 0 0
13 Indirect Expense 4 0 1 0 0
14 Purchase Account 4 0 1 0 0
15 Sundry Creditors 2 1 1 0 0
16 Sundry Debitors 5 1 1 0 0
17 Bank Account 5 1 1 0 0
18 Cash In Hand 5 1 1 0 0
19 Duties & Taxes 2 1 1 0 0
20 Salary 12 1 1 0 0
21 Personal 5 1 1 0 0
22 Loan 2 0 1 0 0
23 Customer 16 1 1 0 0
34 Vendor 15 1 1 0 0
38 Sale Softwares 11 1 1 1 1
46 Stock In Hand 5 1 1 1 1
47 test 1 1 1 1 1
48 test in 47 1 1 1 1
Query to get all groups hierarchy.
declare #ac_no as int =2
;With CTE(grp_id,grp_name,ac_no,Level)
AS
( SELECT
grp_id,grp_name,ac_no,CAST(1 AS int)
FROM
Groups
WHERE
grp_id in (select grp_id from Groups where (ac_no=#ac_no) and grp_of=0)
UNION ALL
SELECT
o.grp_id,o.grp_name,o.ac_no,c.Level+1
FROM
Groups o
INNER JOIN
CTE c
ON c.grp_id=o.ac_no --where o.ac_no=2 and o.grp_of=1
)
select * from CTE
Result is ok for ac_no=2/3/4
grp_id grp_name ac_no Level
----------- ------------------- ----------- ------
5 Current Assets 2 1
6 Fixed Assests 2 1
7 Investment 2 1
8 Misc. Expenses 2 1
22 Loan 2 1
16 Sundry Debitors 5 2
17 Bank Account 5 2
18 Cash In Hand 5 2
21 Personal 5 2
46 Stock In Hand 5 2
23 Customer 16 3
But when I try to get result for ac_no=1;
I get error :
Msg 530, Level 16, State 1, Line 4
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
I think the issue is that you end up in an infinite recursion as you have a row that is it's own parent/child (eg. grp_id = ac_no).
I think it should work if you add a limiting clause to the recursive member like this:
DECLARE #ac_no AS int = 1;
WITH CTE (grp_id , grp_name , ac_no , Level ) AS (
SELECT grp_id, grp_name, ac_no, CAST( 1 AS int )
FROM Groups
WHERE grp_id IN (SELECT grp_id FROM Groups WHERE ac_no = #ac_no AND grp_of = 0)
UNION ALL
SELECT o.grp_id, o.grp_name, o.ac_no, c.Level + 1
FROM Groups o
INNER JOIN CTE c ON c.grp_id = o.ac_no --where o.ac_no=2 and o.grp_of=1
WHERE c.ac_no <> c.grp_id
)
SELECT * FROM CTE;

Where to find the size of SQL Server data types

I am trying to calculate the size of my database. I will have a table with 3 columns (id, int, money) I will have 26 million rows with all columns being occupied. How big will my database be? Also, where can I find the size of all SQL Server data types?
Your can use below query :
SELECT * FROM sys.types
result of above query is below :
name system_type_id user_type_id schema_id principal_id max_length precision scale collation_name is_nullable is_user_defined is_assembly_type default_object_id rule_object_id is_table_type
-------------------- -------------- ------------ --------- ------------ ---------- --------- ----- ----------------- ----------- --------------- ---------------- ----------------- -------------- -------------
image 34 34 4 NULL 16 0 0 NULL 1 0 0 0 0 0
text 35 35 4 NULL 16 0 0 Persian_100_CI_AI 1 0 0 0 0 0
uniqueidentifier 36 36 4 NULL 16 0 0 NULL 1 0 0 0 0 0
date 40 40 4 NULL 3 10 0 NULL 1 0 0 0 0 0
time 41 41 4 NULL 5 16 7 NULL 1 0 0 0 0 0
datetime2 42 42 4 NULL 8 27 7 NULL 1 0 0 0 0 0
datetimeoffset 43 43 4 NULL 10 34 7 NULL 1 0 0 0 0 0
tinyint 48 48 4 NULL 1 3 0 NULL 1 0 0 0 0 0
smallint 52 52 4 NULL 2 5 0 NULL 1 0 0 0 0 0
int 56 56 4 NULL 4 10 0 NULL 1 0 0 0 0 0
smalldatetime 58 58 4 NULL 4 16 0 NULL 1 0 0 0 0 0
real 59 59 4 NULL 4 24 0 NULL 1 0 0 0 0 0
money 60 60 4 NULL 8 19 4 NULL 1 0 0 0 0 0
datetime 61 61 4 NULL 8 23 3 NULL 1 0 0 0 0 0
float 62 62 4 NULL 8 53 0 NULL 1 0 0 0 0 0
sql_variant 98 98 4 NULL 8016 0 0 NULL 1 0 0 0 0 0
ntext 99 99 4 NULL 16 0 0 Persian_100_CI_AI 1 0 0 0 0 0
bit 104 104 4 NULL 1 1 0 NULL 1 0 0 0 0 0
decimal 106 106 4 NULL 17 38 38 NULL 1 0 0 0 0 0
numeric 108 108 4 NULL 17 38 38 NULL 1 0 0 0 0 0
smallmoney 122 122 4 NULL 4 10 4 NULL 1 0 0 0 0 0
bigint 127 127 4 NULL 8 19 0 NULL 1 0 0 0 0 0
hierarchyid 240 128 4 NULL 892 0 0 NULL 1 0 1 0 0 0
geometry 240 129 4 NULL -1 0 0 NULL 1 0 1 0 0 0
geography 240 130 4 NULL -1 0 0 NULL 1 0 1 0 0 0
varbinary 165 165 4 NULL 8000 0 0 NULL 1 0 0 0 0 0
varchar 167 167 4 NULL 8000 0 0 Persian_100_CI_AI 1 0 0 0 0 0
binary 173 173 4 NULL 8000 0 0 NULL 1 0 0 0 0 0
char 175 175 4 NULL 8000 0 0 Persian_100_CI_AI 1 0 0 0 0 0
timestamp 189 189 4 NULL 8 0 0 NULL 0 0 0 0 0 0
nvarchar 231 231 4 NULL 8000 0 0 Persian_100_CI_AI 1 0 0 0 0 0
nchar 239 239 4 NULL 8000 0 0 Persian_100_CI_AI 1 0 0 0 0 0
xml 241 241 4 NULL -1 0 0 NULL 1 0 0 0 0 0
sysname 231 256 4 NULL 256 0 0 Persian_100_CI_AI 0 0 0 0 0 0
CalculatedCreditInfo 243 257 9 NULL -1 0 0 NULL 0 1 0 0 0 1
udt_QoutaDetail 243 258 21 NULL -1 0 0 NULL 0 1 0 0 0 1
BeforeUpdate 243 259 22 NULL -1 0 0 NULL 0 1 0 0 0 1
udt_StoreInventory 243 260 26 NULL -1 0 0 NULL 0 1 0 0 0 1
udt_WKFHistory 243 261 32 NULL -1 0 0 NULL 0 1 0 0 0 1
IDTable 243 262 1 NULL -1 0 0 NULL
you can use max_length for size of each data type.
T-SQL has a function for that: DATALENGTH for all SQL Server versions.
Example:
DECLARE #lat DECIMAL(10, 7) = 3.14151415141514151415;
SELECT #lat, DATALENGTH(#lat);
Result:
3.1415142 and 5 (because DECIMAL(10,7) uses 5 bytes to be stored).
Documentation: https://learn.microsoft.com/en-us/sql/t-sql/functions/datalength-transact-sql?view=sql-server-ver15
For example, I have a table called Applications with these columns: (id VARCHAR(32), debug BIT, connectionString VARCHAR(2048), firebaseKey VARCHAR(4096)). As we know, VARCHAR doesn't allocate all the space (just what you need, so 'A' is 1 byte in VARCHAR).
These queries:
SELECT
SUM(DATALENGTH(id)) AS idSize,
SUM(DATALENGTH(debug)) AS debugSize,
SUM(DATALENGTH(connectionString)) AS connectionStringSize,
SUM(DATALENGTH(firebaseKey)) AS firebaseKeySize
FROM Applications;
SELECT
SUM(
DATALENGTH(id) +
DATALENGTH(debug) +
DATALENGTH(connectionString) +
DATALENGTH(firebaseKey)
) AS totalSize
FROM Applications;
will return my data size (in my case, with my rows, is 8, 2, 366, 4698 (total: 5074). There are 2 rows in that table.
Notice that this does NOT represent the total size of my database (there are pages, descriptors, indexes, etc. involved.)*
MSSQL has internal stored procedures to tell you the exactly size of your database in disk:
EXEC sp_spaceused; for all database;
EXEC sp_spaceused N'schema.TableName'; for a specific table;
EXEC sp_helpdb N'DatabaseName'; if you want details from each file.
http://msdn.microsoft.com/en-us/library/ms187752.aspx
Money : 8 bytes
int : 4 bytes
id - depends on what you mean.
If the table specified in the where clause contains a nvarchar, this query will give you how many characters there are for that column correctly!
This detects if the column is "wide" and essentially divides by 2. More broad than just nvarchar.
SELECT c.name, (CASE WHEN LEFT(ts.name, 1) = 'n' AND ts.[precision] = 0 AND ts.[scale] = 0 THEN c.max_length / ts.[bytes] ELSE c.max_length END) AS [length]
FROM sys.columns AS c
INNER JOIN sys.tables AS t
ON t.object_id = c.object_ID
INNER JOIN
(
SELECT *, (CASE WHEN [bits] = -1 THEN -1 ELSE ([bits] + 7) / 8 END) AS [bytes]
FROM (
SELECT *, (CASE WHEN max_length >= 256 THEN (CASE WHEN LEFT(name, 1) = 'n' AND [precision] = 0 AND [scale] = 0 THEN 16 ELSE 8 END) ELSE max_length END) AS [bits]
FROM sys.types AS iits
) AS its
) AS ts
ON ts.user_type_id = c.user_type_id
WHERE t.name LIKE 'tb_tablename' -- LIKE is case insensitive
Of course, you can just divide max_length on sys.columns by 2 if you know the column is an nvarchar. This is more for discovering table schema in a way that seems better for if new sql data types are introduced in the future. And you so-choose to upgrade to it. Pretty small edge case.
Please edit and correct this answer if you find an edge case where
bytes and bits are incorrect.
Details:
-- ([bits] + 7) / 8 means round up
--
-- Proof:
-- o (1 bit + 7 = 8) / 8 = 1 byte used
-- o ((8 + 8 + 1 = 17 bytes) + 7 = 24) / 8 = 3 byes used
-- o ((8 + 8 + 7 = 23 bytes) + 7 = 30) / 8 = 3.75 = integer division removes decimal = 3
SELECT *, (CASE WHEN [bits] = -1 THEN -1 ELSE ([bits] + 7) / 8 END) AS [bytes]
FROM (
SELECT *, (CASE WHEN max_length >= 256 THEN (CASE WHEN LEFT(name, 1) = 'n' AND [precision] = 0 AND [scale] = 0 THEN 16 ELSE 8 END) ELSE max_length END) AS [bits]
FROM sys.types AS its
) AS ts
If someone knows that SQL Server stores the bit and byte sizes for each data type. Or a better way to get sys.columns size, please leave a comment!

Resources