Generate report from a table - sql-server

I have a table like:
+====+========+========+
| Id | name | value |
+====+========+========+
| 1 | a | 7 |
+----+--------+--------+
| 2 | c | 7 |
+----+--------+--------+
| 1 | g | 1 |
+----+--------+--------+
| 2 | c | 2 |
+----+--------+--------+
| 4 | g | 5 |
+----+--------+--------+
| 6 | t | 4 |
+----+--------+--------+
I need to write two (2) queries to generate two reports, according to this two conditions:
Report Output1=if id and name same (id,name,val)
Report Output2=if id same but different name(id,name,val)
How to write those two queries?

Your conditions is not clear, but mybe this what you want:
DECLARE #T TABLE (Id INT, Name VARCHAR(25), Value INT);
DECLARE #YourId INT = 1;
DECLARE #YourName VARCHAR(25) ='a';
/**/
INSERT INTO #T VALUES
(1, 'a', 7),
(2, 'c', 7),
(1, 'g', 1),
(2, 'c', 2),
(4, 'g', 5),
(6, 't', 4);
/*First query*/
SELECT *
FROM #T
WHERE ID = #YourID AND Name = #YourName;
/*Second query*/
SELECT *
FROM #T
WHERE ID = #YourID;
If you want the result of both queries in one result, then you can use UNION ALL as:
SELECT *
FROM #T
WHERE ID = #YourID AND Name = #YourName
UNION ALL
SELECT *
FROM #T
WHERE ID = #YourID;
Demo.

Well, I am not sure, what OP wanted, but maybe it was something like this?
// records where id and value are the same
SELECT * FROM #T WHERE ID=Value;
// other records having the same ids as abobe, but DIFFERENT values
SELECT * FROM #T WHERE ID IN
(SELECT ID FROM #T WHERE ID=Value)
AND Id!=Value;
Results:
   Id Name Value
1 g 1
2 c 2
   Id Name Value
1 a 7
2 c 7
Thanks to #Sami for providing the fiddle which I modified into this DEMO.

Related

SQL Server split field and create addition rows with values from main row

I have a table with rows and in one field there are values like this A,B,C
Table 'Mytable':
|ID | Date | MyValue | SplitID |
|1 | 2019-12-17 | A | |
|2 | 2019-12-15 | A,B | |
|3 | 2019-12-16 | B,C | |
Result should be:
|1 | 2019-12-17 | A | 1 |
|2 | 2019-12-15 | A | 2 |
|4 | 2019-12-15 | B | 2 |
|3 | 2019-12-16 | B | 3 |
|5 | 2019-12-16 | C | 3 |
(Sorry, I could not find HOW to format a table in the Stackoverflow help)
I tried a inline table function which splits the Field Myvalue into more lines but could not pass my rows with
charindex(',',[MyValue])>0
from MyTable as input lines.
The code is this:
ALTER function [dbo].[fncSplitString](#input Varchar(max), #Splitter Varchar(99), #ID int)
returns table as
Return
with tmp (DataItem, ix, ID) as
( select LTRIM(#input) , CHARINDEX('',#Input), #ID --Recu. start, ignored val to get the types right
union all
select LTRIM(Substring(#input, ix+1,ix2-ix-1)), ix2, #ID
from (Select *, CHARINDEX(#Splitter,#Input+#Splitter,ix+1) ix2 from tmp) x where ix2<>0
) select DataItem,ID from tmp where ix<>0
Thanks for help
Michael
You can try the following query.
Create table #Temp(
Id int,
DateField Date,
MyValue Varchar(10),
SplitID int
)
CREATE FUNCTION [dbo].[SplitPra] (#Value VARCHAR(MAX), #delimiter CHAR)
RETURNS #DataResult TABLE([Position] TINYINT IDENTITY(1,1),[Value] NVARCHAR(128))
AS
BEGIN
DECLARE #XML xml = N'<r><![CDATA[' + REPLACE(#Value, #delimiter, ']]></r><r><![CDATA[') + ']]></r>'
INSERT INTO #DataResult ([Value])
SELECT RTRIM(LTRIM(T.c.value('.', 'NVARCHAR(128)')))
FROM #xml.nodes('//r') T(c)
RETURN
END
insert into #Temp Values(1, '2019-12-17', 'A', NULL),(2, '2019-12-15', 'A,B', NULL), (3, '2019-12-16', 'B,C', NULL)
Select
#Temp.Id, DateField, b.Value as MyValue, b.Id as SplitValue
from #Temp inner join (
select
Id, f.*
from
#Temp u
cross apply [dbo].[SplitPra](u.MyValue, ',') f
)b on #Temp.Id = b.Id
Drop table #Temp
This will give an output as shown below.
Id DateField MyValue SplitValue
---------------------------------
1 2019-12-17 A 1
2 2019-12-15 A 2
2 2019-12-15 B 2
3 2019-12-16 B 3
3 2019-12-16 C 3
You can find the live demo here.
I found this solution, i hope it will work for you. But i didn't use your function to solve this problem. Instead of that, i used cross apply function.You can find the query below:
-- Creating Test Table
CREATE TABLE #Test
(
ID int,
Date date,
MyValue nvarchar(max),
SplitID int
);
GO
-- Inserting data into test table
INSERT INTO #Test VALUES (1, '2019-12-17', 'A', NULL);
INSERT INTO #Test VALUES (2, '2019-12-15', 'A,B', NULL);
INSERT INTO #Test VALUES (3, '2019-12-16', 'B,C', NULL);
GO
-- Select query
SELECT
*,
(SELECT ID FROM test t1 WHERE t.Date = t1.date) AS SplitID
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY ID) AS ID,
Date,
substring(A.value,1,
CASE WHEN charindex(',',rtrim(ltrim(A.value))) = 0 then LEN(A.value)
ELSE charindex(',',rtrim(ltrim(A.value))) -1 end) as MyValue
FROM Test
CROSS APPLY string_split (MyValue, ',') A) AS T
ORDER BY MyValue ASC;
And the result must be like that:
ID Date MyValue SplitID
1 2019-12-17 A 1
2 2019-12-15 A 2
3 2019-12-15 B 2
4 2019-12-16 B 3
5 2019-12-16 C 3

Merge multiple results to one Column

I would like to create a select statement to merge multiple results into one rot
I was able to realized what I want via PHP but i think it should be possible to work directly with Sql.
Notes
| ID | Name |
|----|------|
| 2 | Test |
| 3 | Test |
EditorAssignment
| UserID | NoteID |
|--------|--------|
| 1 | 2 |
| 2 | 2 |
UserList
| ID | username |
|----|----------|
| 1 | testuser |
| 2 | bUser |
| 3 | cUser |
I would like to have the following Result:
| NoteID | User |
|--------|-----------------|
| 2 | testuser, bUser |
| 3 | cUser |
How can i create a select like that in SQL2012?
Before SQL Server 2017 (which has STRING_AGG aggregate function for this), you need to use the famous FOR XML PATH correlated subquery:
SetUp:
DECLARE #Notes TABLE (ID INT, Name VARCHAR(10))
INSERT INTO #Notes (ID, Name)
VALUES (2, 'Test'), (3, 'Test')
DECLARE #EditorAssignment TABLE (UserID INT, NoteID INT)
INSERT INTO #EditorAssignment (UserID, NoteID)
VALUES (1, 2), (2, 2),
(3, 3) -- Added missing row here
DECLARE #UserList TABLE (ID INT, username VARCHAR(100))
INSERT INTO #UserList (ID, username)
VALUES (1, 'testuser'), (2, 'bUser'), (3, 'cUser')
Query:
SELECT
NoteID = N.ID,
[User] = STUFF(
(
SELECT
', ' + U.username
FROM
#EditorAssignment AS E
INNER JOIN #UserList AS U ON E.UserID = U.ID
WHERE
N.ID = E.NoteID -- Link the outmost Notes' note with the inner EditorAssignment (correlated subquery)
FOR XML
PATH ('') -- FOR XML PATH('') makes the SELECT return a string value, not a result set
),
1,
2,
'')
FROM
#Notes AS N
Results:
NoteID User
2 testuser, bUser
3 cUser
The subquery generates a string with each username for the related assignment for each note.
The STUFF function is used just to replace the first ', ', since the string is build with a leading comma and a space. This is why the parameters of the STUFF are 1 (first position of the string), 2 (amount of places to remove, the comma and the space), and '' (replacement for those characters).
I'm guessing that you have a row missing for the EditorAssignment table that holds the values 3, 3 on your example.

Track the changes of a few columns in an existing table leveraging primary keys?

I'm currently trying to track the changes of a few columns (let's call them col1 & col2) in a SQL Server table. The table is not being "updated/inserted/deleted" over time; new records are just being added to it (please see below 10/01 vs 11/01).
My end-goal would be to run a SQL query or stored procedure that would highlight the changes overtime using primary keys following the framework:
PrimaryKey | ColumnName | BeforeValue | AfterValue | Date
e.g.
Original table:
+-------+--------+--------+--------+
| PK1 | Col1 | Col2 | Date |
+-------+--------+--------+--------+
| 1 | a | e | 10/01 |
| 1 | b | e | 11/01 |
| 2 | c | e | 10/01 |
| 2 | d | f | 11/01 |
+-------+--------+--------+--------+
Output:
+--------------+--------------+---------------+--------------+--------+
| PrimaryKey | ColumnName | BeforeValue | AfterValue | Date |
+--------------+--------------+---------------+--------------+--------+
| 1 | Col1 | a | b | 11/01 |
| 2 | Col1 | c | d | 11/01 |
| 2 | Col2 | e | f | 11/01 |
+--------------+--------------+---------------+--------------+--------+
Any help appreciated.
Here is some code which is a bit clunky, but seems to work, Basically for each row I try and find an earlier row with a different value. This is done twice, once for Col1 and once for Col2.
To make it work I had to add a unique PK field, which I don't know whether you have or not, you can easily add as an identify field, either to your real table, or to the table used for the calculations.
declare #TestTable table (PK int, PK1 int, Col1 varchar(1), Col2 varchar(1), [Date] date)
insert into #TestTable (PK, PK1, Col1, Col2, [Date])
select 1, 1, 'a', 'e', '10 Jan 2018'
union all select 2, 1, 'b', 'e', '11 Jan 2018'
union all select 3, 2, 'c', 'e', '10 Jan 2018'
union all select 4, 2, 'd', 'f', '11 Jan 2018'
select T1.[Date], T1.PK1, 'Col1', T2.Col1, T1.Col1
from #TestTable T1
inner join #TestTable T2 on T2.PK = (
select top 1 PK
from #TestTable T21
where T21.PK1 = T1.PK1 and T21.Col1 != T1.Col1 and T21.[Date] < T1.[Date]
order by T21.[Date] desc
)
union all
select T1.[Date], T1.PK1, 'Col2', T3.Col2, T1.Col2
from #TestTable T1
inner join #TestTable T3 on T3.PK = (
select top 1 PK
from #TestTable T31
where T31.PK1 = T1.PK1 and T31.Col2 != T1.Col2 and T31.[Date] < T1.[Date]
order by T31.[Date] desc
)
order by [Date], PK1

What sql statement will give me this result?

I do not know how to word my question properly. My apologies for that. I have a table like this:
EventId | Item | Type
--------+------+------
1 | 123 | A
2 | 123 | B
3 | 123 | C
4 | 456 | A
5 | 456 | B
I want to select only those items that do not have event of type C. Then only show event of type B of those items. So, the result should look like this:
EventId | Item | Type
--------+------+-------
5 | 456 | B
This should do the trick...
IF OBJECT_ID('tempdb..#Event', 'U') IS NOT NULL
DROP TABLE #Event;
CREATE TABLE #Event (
EventId INT NOT NULL PRIMARY KEY,
Item INT NOT NULL,
ItemType CHAR(1) NOT NULL
);
INSERT #Event (EventId, Item, ItemType) VALUES
(1, 123, 'A'),
(2, 123, 'B'),
(3, 123, 'C'),
(4, 456, 'A'),
(5, 456, 'B');
--=======================================
SELECT
e1.EventId, e1.Item, e1.ItemType
FROM
#Event e1
WHERE
e1.ItemType = 'B'
AND NOT EXISTS (
SELECT 1
FROM #Event e2
WHERE
e1.Item = e2.Item
AND e2.ItemType = 'C'
);
Results...
EventId Item ItemType
----------- ----------- --------
5 456 B
You answer based on said constrain
SELECT
e1.EventId, e1.Item, e1.ItemType
FROM
Event e1
INNER JOIN Event e2 ON e1.Item != e2.Item
WHERE e1.ItemType = 'B'
AND e2.ItemType = 'C'
Output:
Note: Inner SELECT query may cause the performance issue while processing large number of records comparing to INNER JOIN

T SQL Pivot still one row per pivot column

I am trying to create a pivot table in SQL 2008R2. I'm trying to reproduce and Access Pivot table in SQL. When I run the following script, I get one record for each pivot column instead of one record with two populated pivoted columns.
SELECT * FROM
(SELECT DataView.MAEID
, DataView.MoYr
, DataView.ChemicalName
, TblCategories.CatDesc
, DataView.[CAS#]
, DataView.HAP
, Sum([SpecAE]/2000) AS [Total SpecAE Tons]
, SUM([SpecAE]) AS [SpecAE]
FROM TblCategories
INNER JOIN DataView
ON TblCategories.CatID = DataView.Category
GROUP BY DataView.MAEID
, DataView.MoYr
, DataView.ChemicalName
, DataView.[CAS#]
, DataView.HAP
, TblCategories.CatDesc) TBL
PIVOT (
Sum([SpecAE])
FOR CatDesc IN ([INCIINERABLE LIQUIDS], [Supplemental Fuels])
)pvt
Any thoughts?
You haven't provided sample data, so I'll explain your issue with an example. Let's say I have a very simple table with some very simple values:
DECLARE #T TABLE
(
MainColumn INT NOT NULL,
PivotColumn INT NOT NULL,
SumColumn INT NOT NULL
);
INSERT #T VALUES
(1, 1, 10), (1, 1, 20), (1, 1, 30),
(1, 2, 60),
(1, 3, 50),
(2, 1, 10), (2, 1, 15),
(2, 2, 20),
(3, 1, 10),
(3, 2, 10),
(4, 1, 150);
If I perform the following query:
SELECT MainColumn,
PivotColumn,
PivotValue = SUM(SumColumn),
OtherSum = SUM(SumColumn / 5)
FROM #T
GROUP BY MainColumn, PivotColumn
ORDER BY MainColumn, PivotColumn
I get:
+------------+-------------+------------+----------+
| MainColumn | PivotColumn | PivotValue | OtherSum |
+------------+-------------+------------+----------+
| 1 | 1 | 60 | 12 |
| 1 | 2 | 60 | 12 |
| 1 | 3 | 50 | 10 |
| 2 | 1 | 25 | 5 |
| 2 | 2 | 20 | 4 |
| 3 | 1 | 10 | 2 |
| 3 | 2 | 10 | 2 |
| 4 | 1 | 150 | 30 |
+------------+-------------+------------+----------+
Now if I use a PIVOT to pivot the PivotValue for each PivotColumn, it's going to group by MainColumn AND OtherSum column. A pivot groups by every column that isn't part of the pivot.
So my result set will be split into (MainColumn=1, OtherSum=12), (MainColumn=1, OtherSum=10), (MainColumn=2, OtherSum=5), (MainColumn=2, OtherSum=4), etc... I will get a new line for each of these values. If the OtherSum value was unique for each line, I'd expect 8 lines with a pivot.
If I remove OtherSum from my result set, my result set is just going to group by MainColumn alone, so it'll all be on one line for each distinct MainColumn value, since that's the only column the pivot would group by.
If getting the other sum value is important, I can do something like the following:
SELECT P.MainColumn,
Val1A = P.[1],
Val1B = P.[1] / 5,
Val2A = P.[2],
Val2B = P.[2] / 5,
Val3A = P.[3],
Val3B = P.[3] / 5
FROM
(
SELECT MainColumn,
PivotColumn,
PivotValue = SUM(SumColumn)
FROM #T
GROUP BY MainColumn, PivotColumn
) AS T
PIVOT
(
SUM(PivotValue) FOR PivotColumn IN ([1], [2], [3])
) AS P;

Resources