how to find records which has some specific values - sql-server

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

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"

Use Sum on extra aggregation and Make Total

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"

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

SQL Server order by syntax with Case When and a Constant

I'm reading TSQL code someone else wrote and find a somewhat weird syntax. It's doing order by a string. I did some test and the following is the code. Anyone can help me to explain it? Thanks.
First Query
SELECT *
FROM dbo.Products
Result:
ProductID ProductName SupplierID CategoryID QuantityPerUnit UnitPrice UnitsInStock UnitsOnOrder ReorderLevel Discontinued
----------- ------------------------------- ----------- ----------- -------------------- --------------------- ------------ ------------ ------------ ------------
1 Chai 1 1 10 boxes x 20 bags 18.00 39 0 10 0
2 Chang 1 1 24 - 12 oz bottles 19.00 17 40 25 0
3 Aniseed Syrup 1 2 12 - 550 ml bottles 10.00 13 70 25 0
4 Chef Anton's Cajun Seasoning 2 2 48 - 6 oz jars 22.00 53 0 0 0
...
*/
Second query:
SELECT *
FROM dbo.Products
WHERE ProductID < 10
ORDER BY '3';
Result:
Msg 408, Level 16, State 1, Line 1 A constant expression was
encountered in the ORDER BY list, position 1.
Third Query
SELECT *
FROM dbo.Products
WHERE ProductID < 10
ORDER BY CASE WHEN SupplierID = 2 THEN '1'
WHEN SupplierID = 1 THEN '2'
ELSE '3'
END;
Result:
ProductID ProductName SupplierID CategoryID QuantityPerUnit UnitPrice UnitsInStock UnitsOnOrder ReorderLevel Discontinued
----------- ---------------------------------------- ----------- ----------- -------------------- --------------------- ------------ ------------ ------------ ------------
4 Chef Anton's Cajun Seasoning 2 2 48 - 6 oz jars 22.00 53 0 0 0
5 Chef Anton's Gumbo Mix 2 2 36 boxes 21.35 0 0 0 1
1 Chai 1 1 10 boxes x 20 bags 18.00 39 0 10 0
2 Chang 1 1 24 - 12 oz bottles 19.00 17 40 25 0
3 Aniseed Syrup 1 2 12 - 550 ml bottles 10.00 13 70 25 0
6 Grandma's Boysenberry Spread 3 2 12 - 8 oz jars 25.00 120 0 25 0
7 Uncle Bob's Organic Dried Pears 3 7 12 - 1 lb pkgs. 30.00 15 0 10 0
8 Northwoods Cranberry Sauce 3 2 12 - 12 oz jars 40.00 6 0 0 0
9 Mishi Kobe Niku 4 6 18 - 500 g pkgs. 97.00 29 0 0 1
(9 row(s) affected)
*/
"Order by" has to be able to translate each row into a value, then those values can be compared. "Order by '3'" doesn't make any sense as a useful query, as it's not using the row - hence the error message of ordering by a constant expression.
"Order by (some expression returning a string)" makes perfect sense. I would personally have used numbers rather than strings, but fundamentally it's still just ordering by a value.
Would you have found it odd to see "order by ProductName"? That's ordering by a string too.
Hopefully that helps - it's not really clear which bit was causing a problem though.
In your first SQL query, the original coder might have meant
ORDER BY 3
which means "order by the 3rd column" (which is SupplierId), in ascending order.
In the second query, as #Kokizzo has explained, the author has hard coded the query so that Products from supplierId 2 are at the top, followed by those from supplierId 1, and then all rows from other suppliers. The purpose isn't clear, but for example, this could be a nefarious attempt to promote a certain supplier's products above others e.g. in a web search result page.
The CASE WHEN .. ELSE ... END can be equated to a simple function applied to each row, which takes the supplierId as input and returns the precedence of that row used in the ORDER BY clause.
CASE WHEN SupplierID = 2 THEN '1'
WHEN SupplierID = 1 THEN '2'
ELSE '3'
END
is equal to (in pseudocode):
if supplierId = 2 then
order_value = 1
else if supplierId = 1 then
order_value = 2
else
order_value = 3
end
so the order now is according to the order_value

TSQL: non-boolean type specified error using update in a trigger

I'm trying to use the update function in T-sql in a trigger to check if a column has been changed or not. This is what I'm doing:
declare column_name cursor for select name from sys.columns where object_id = object_id(N'tblKit')
open column_name
fetch column_name into #colname
while (##Fetch_status=0)
begin
if(Update(#colname))
I get an error saying non-boolean type specified where a condition is expected. This is the syntax used in the msdn forum. So is there anything wrong with this?
I'm using Microsoft SQL server 2008 with Management Studio
If you simply want to log changes of individual columns in your trigger, you could try unpivoting, possibly in conjunction with full join. The idea is, you unpivot both inserted and deleted then join them on the table's key and the column containing the unpivoted names, filtering out the rows where the values are same.
Here's an example illustration of the method.
First, the table definitions:
CREATE TABLE TestTable (
ID int IDENTITY PRIMARY KEY,
Attr1 int,
Attr2 int,
Attr3 int
);
CREATE TABLE TestTableLog (
ID int IDENTITY PRIMARY KEY,
TableID int,
AttrName sysname,
OldValue int,
NewValue int,
Timestamp datetime DEFAULT GETDATE()
);
Next, a trigger for logging changes. This one will catch all the operations: insert, update, and delete:
CREATE TRIGGER trTestTable ON TestTable
AFTER INSERT, UPDATE, DELETE
AS BEGIN
WITH inserted_unpivot AS (
SELECT
ID,
AttrName,
Value
FROM inserted i
UNPIVOT (Value FOR AttrName IN (Attr1, Attr2, Attr3)) u
),
deleted_unpivot AS (
SELECT
ID,
AttrName,
Value
FROM deleted d
UNPIVOT (Value FOR AttrName IN (Attr1, Attr2, Attr3)) u
)
INSERT INTO TestTableLog (TableID, AttrName, OldValue, NewValue)
SELECT
ISNULL(i.ID, d.ID),
ISNULL(i.AttrName, d.AttrName),
d.Value,
i.Value
FROM inserted_unpivot i
FULL JOIN deleted_unpivot d
ON i.ID = d.ID AND i.AttrName = d.AttrName
WHERE CASE i.Value WHEN d.Value THEN 0 ELSE 1 END = 1
END
Now let's fill the TestTable with some data:
WHILE (SELECT COUNT(*) FROM TestTable) < 15
INSERT INTO TestTable
SELECT RAND() * 1000, RAND() * 1000, RAND() * 1000
;
Here's its contents before the subsequent changes:
ID Attr1 Attr2 Attr3
----------- ----------- ----------- -----------
1 820 338 831
2 795 881 453
3 228 430 719
4 36 236 105
5 246 115 649
6 488 657 438
7 990 360 15
8 668 978 724
9 872 385 562
10 460 396 462
11 62 599 630
12 145 815 439
13 595 7 54
14 587 85 655
15 80 606 407
And now let's perform some modifications to the contents:
UPDATE TestTable SET Attr2 = 35 WHERE ID = 3;
UPDATE TestTable SET Attr3 = 0 WHERE ID BETWEEN 6 AND 10;
INSERT INTO TestTable VALUES (1, 1, 1);
DELETE FROM TestTable WHERE ID = 14;
Here's what we've got in TestTable afterwards:
ID Attr1 Attr2 Attr3
----------- ----------- ----------- -----------
1 820 338 831
2 795 881 453
3 228 35 719
4 36 236 105
5 246 115 649
6 488 657 0
7 990 360 0
8 668 978 0
9 872 385 0
10 460 396 0
11 62 599 630
12 145 815 439
13 595 7 54
15 80 606 407
16 1 1 1
And this is what has been logged:
ID TableID AttrName OldValue NewValue Timestamp
----------- ----------- ----------- ----------- ----------- -----------------------
1 3 Attr2 430 35 2011-08-22 20:12:19.217
2 10 Attr3 462 0 2011-08-22 20:12:19.227
3 9 Attr3 562 0 2011-08-22 20:12:19.227
4 8 Attr3 724 0 2011-08-22 20:12:19.227
5 7 Attr3 15 0 2011-08-22 20:12:19.227
6 6 Attr3 438 0 2011-08-22 20:12:19.227
7 16 Attr1 NULL 1 2011-08-22 20:12:19.227
8 16 Attr3 NULL 1 2011-08-22 20:12:19.227
9 16 Attr2 NULL 1 2011-08-22 20:12:19.227
10 14 Attr1 587 NULL 2011-08-22 20:12:19.230
11 14 Attr2 85 NULL 2011-08-22 20:12:19.230
12 14 Attr3 655 NULL 2011-08-22 20:12:19.230
The setup, of course, has been somewhat simplified. In particular, all the main table's columns that are to be logged are of the same type, and so there's no need to convert data to some generic type to embrace various kinds of data. But maybe that's just what you need. And if not, I believe this can provide a good start to implementing the ultimate solution.

Resources