With One Select Statement how To Get The Following Table Result - sql-server

In this the output need to get is that the value from the each id that should have only one value assign to that id(col1). if the same id has diff value no need to take that values and output.
Below is a sample table
Input Table 'Demo'
col1 col2
100 A
100 A
100 A
100 A
101 A
101 B
102 A
102 B
102 B
102 C
Output
col1 col2
100 A
100 A
100 A
100 A

You can use not exists :
select d.*
from Demo d
where not exists (select 1 from Demo d1 where d1.col1 = d.col1 and d1.col2 <> d.col2);

Related

SQLite: Return NULL fields in multiple LEFT JOIN Table

I have a cumbersome query I'm building in a certain way as I'll be calling it from the C-API substituting certain values. I'm having an issue where I'm expecting NULL fields to be populating the final table.
To populate my query, I generate a date column using a recursive table expression and joining another table twice.
An example set from my table's data:
SELECT * FROM myTable;
id foreignId date value
---------- ---------- ---------- ----------
1 1 2019-12-01 100
2 1 2019-12-02 101
3 1 2019-12-03 102
4 1 2019-12-04 103
5 1 2019-12-07 104
6 2 2019-12-01 200
7 2 2019-12-02 201
8 2 2019-12-03 202
9 2 2019-12-07 203
The query I'm using:
WITH RECURSIVE dates(date) AS (
VALUES('2019-12-01')
UNION ALL
SELECT date(date, '+1 day')
FROM dates
WHERE date < '2019-12-07'
)
SELECT a.date, b.myTable, c.myTable
FROM dates a
LEFT JOIN myTable b ON a.date = b.date
LEFT JOIN myTable c ON a.date = c.date
WHERE b.foreignId = 1 AND c.foreignId = 2;
Returns the table:
date myTable myTable
---------- ---------- ----------
2019-12-01 100 200
2019-12-02 101 201
2019-12-03 102 202
2019-12-07 104 203
What I am trying to achieve:
date myTable myTable
---------- ---------- ----------
2019-12-01 100 200
2019-12-02 101 201
2019-12-03 102 202
2019-12-04 103
2019-12-05
2019-12-06
2019-12-07 104 203
I've tried using IFNULL in the SELECT statement like:
...
SELECT a.date, IFNULL(b.myTable, 0) b.myTable, IFNULL(c.myTable, 0) c.myTable
...
Which returns:
Error: near ".": syntax error
I'm not certain what the syntax error is, and haven't got that part working to test the result.
I've also tried using CROSS JOIN in place of LEFT JOIN and various combinations, but they return the same table as the LEFT JOIN. Can anyone give me some guidance, particularly anything in the documentation I may have missed?
Move the condition on the left joined tables from the where clause to the on part of the join. Otherwise, rows where the left join comes up empty are filtered out by the where clause (since the conditions are not be fulfilled): this actually turns your left join to an inner join.
WITH RECURSIVE dates(date) AS ( ...)
SELECT a.date, b.myTable, c.myTable
FROM dates a
LEFT JOIN myTable b ON a.date = b.date AND b.foreignId = 1
LEFT JOIN myTable c ON a.date = c.date AND c.foreignId = 2;

How would you write a T-SQL query that supported event study analysis

I trying to create a table that will support a simple event study analysis, but I'm not sure how best to approach this.
I'd like to create a table with the following columns: Customer, Date, Time on website, Outcome. I'm testing the premise that the outcome for a particular customer on any give day if a function of the time spent on the website on the current day as well as the preceding five site visits. I'm envisioning a table similar to this:
I'm hoping to write a T-SQL query that will produce an output like this:
Given this objective, here are my questions:
Assuming this is indeed possible, how should I structure my table to accomplish this objective? Is there a need for a column that refers to the prior visit? Do I need to add an index to a particular column?
Would this be considered a recursive query?
Given the appropriate table structure, what would the query look like?
Is it possible to structure the query with a variable that determines the number of prior periods to include in addition to the current period (for example, if I want to compare 5 periods to 3 periods)?
Not sure I understand analytic value of your matrix
Declare #Table table (id int,VisitDate date,VisitTime int,Outcome varchar(25))
Insert Into #Table (id,VisitDate,VisitTime,Outcome) values
(123,'2015-12-01',100,'P'),
(123,'2016-01-01',101,'P'),
(123,'2016-02-01',102,'N'),
(123,'2016-03-01',100,'P'),
(123,'2016-04-01', 99,'N'),
(123,'2016-04-09', 98,'P'),
(123,'2016-05-09', 99,'P'),
(123,'2016-05-14',100,'N'),
(123,'2016-06-13', 99,'P'),
(123,'2016-06-15', 98,'P')
Select *
,T0 = VisitTime
,T1 = Lead(VisitTime,1,0) over(Partition By ID Order By ID,VisitDate Desc)
,T2 = Lead(VisitTime,2,0) over(Partition By ID Order By ID,VisitDate Desc)
,T3 = Lead(VisitTime,3,0) over(Partition By ID Order By ID,VisitDate Desc)
,T4 = Lead(VisitTime,4,0) over(Partition By ID Order By ID,VisitDate Desc)
,T5 = Lead(VisitTime,5,0) over(Partition By ID Order By ID,VisitDate Desc)
From #Table
Order By ID,VisitDate Desc
Returns
id VisitDate VisitTime Outcome T0 T1 T2 T3 T4 T5
123 2016-06-15 98 P 98 99 100 99 98 99
123 2016-06-13 99 P 99 100 99 98 99 100
123 2016-05-14 100 N 100 99 98 99 100 102
123 2016-05-09 99 P 99 98 99 100 102 101
123 2016-04-09 98 P 98 99 100 102 101 100
123 2016-04-01 99 N 99 100 102 101 100 0
123 2016-03-01 100 P 100 102 101 100 0 0
123 2016-02-01 102 N 102 101 100 0 0 0
123 2016-01-01 101 P 101 100 0 0 0 0
123 2015-12-01 100 P 100 0 0 0 0 0
With fixed columns you can do it like this with lag:
select
time,
lag(time, 1) over (partition by customer order by date desc),
lag(time, 2) over (partition by customer order by date desc),
lag(time, 3) over (partition by customer order by date desc),
lag(time, 4) over (partition by customer order by date desc)
from
yourtable
If you need dynamic columns, then you'll have to build it using dynamic SQL.

Joining two SQL tables based on the equality of few columns

I am trying to Create a SQL View by joining two SQL tables and return only the lowest value from second table and all the rows from first table similar to left join.
My problem can be clearly explained with the below example.
Table1
Id Product Grade Term Bid Offer
100 ABC A Q1 10 20
101 ABC A Q1 5 25
102 XYZ A Q2 25 30
103 XYZ B Q2 20 30
Table2
Id Product Grade Term TradeValue
1 ABC A Q1 100
2 ABC A Q1 95
3 XYZ B Q2 100
In the above data I want to join Table1 and Table2 when ever the columns Product,Grade and Term from both the tables are equal and return all the rows from Table1 while joining the lowest Value of the column TradeValue from Table2 to the first record of the match and making TradeValue as NULL for other rows of the resultant View and the resultant View should have the Id of Table2 as LTID
So the resultant SQL View should be
RESULT
Id Product Grade Term Bid Offer TradeValue LTID
100 ABC A Q1 10 20 95 2
101 ABC A Q1 5 25 NULL 2
102 XYZ A Q2 25 30 NULL NULL
103 XYZ B Q2 20 30 100 3
I tried using the following query
CREATE VIEW [dbo].[ViewCC]
AS
SELECT
a.Id,a.Product,a.Grade,a.Term,a.Bid,a.Offer,
b.TradeValue
FROM Table1 AS a
left JOIN (SELECT Product,Grade,Term,MIN(TradeValue) TradeValue from Table2 Group by Product,Grade,Term,) AS b
ON b.Product=a.Product
and b.Grade=a.Grade
and b.Term=a.Term
GO
The above Query returned the following data which is apt to the query I wrote but that is not what I was trying to get
Id Product Grade Term Bid Offer TradeValue
100 ABC A Q1 10 20 95
101 ABC A Q1 5 25 95 --This should be null
102 XYZ A Q2 25 30 NULL
103 XYZ B Q2 20 30 100
As we can see minimum value of TradeValue being assigned to all matching rows in Table1 and also I was not able to return Id As LTID from Table2 as I have issues with group by clause as I cannot group it by b.Id as it returns too many rows.
May I know a better way to deal with this?
You need a row number attached to each record from Table1, so that the requirement of only joining the first record from each group of Table1 can be fulfilled:
CREATE VIEW [dbo].[ViewCC]
AS
SELECT a.Id, a.Product, a.Grade, a.Term, a.Bid, a.Offer,
b.TradeValue, b.Id AS LTID
FROM (
SELECT *, ROW_NUMBER() OVER(PARTITION BY Product, Grade, Term ORDER BY Id) AS rn
FROM Table1
) a
OUTER APPLY (
SELECT TOP 1 CASE WHEN rn = 1 THEN TradeValue
ELSE NULL
END AS TradeValue, Id
FROM Table2
WHERE Product=a.Product AND Grade=a.Grade AND Term=a.Term
ORDER BY TradeValue) b
GO
OUTER APPLY returns a table expression containing either the matching record from Table2 with the lowest TradeValue, or NULL if no matching record exists.

Select rows from table representing an object's changing of state ignoring no-change rows

In a sqlite database I have the following table:
id object val1 val2 'time stamp'
1 Z 100 102 53
2 Z 100 102 54
3 Z 100 103 55
4 A 99 123 23
5 A 23 245 35
6 A 23 245 36
7 A 23 245 37
8 A 23 245 38
9 A 99 123 119
For all kind of objects the values val1 and val2 are recorded with a time stamp.
How can I select all rows contaning a change in one of the value fields for each object.
Hence I want a select statement with the following result:
id object val1 val2 'time stamp'
1 Z 100 102 53
3 Z 100 103 55
4 A 99 123 23
5 A 23 245 35
9 A 99 123 119
Can somebody help me out with the correct sql query. Thank you.
For a record with object O and timestamp T, the following query will find the values for the relevant previous record, i.e., the record with the largest timestamp that is still smaller than T:
SELECT val1, val2
FROM MyTable
WHERE object = O
AND "time stamp" < T
ORDER BY "time stamp" DESC
LIMIT 1
By using something like this as a subquery, we can get both sets of values to compare them:
SELECT *
FROM MyTable AS T1
WHERE val1 || ',' || val2 IS NOT (SELECT T2.val1 || ',' || T2.val2
FROM MyTable AS T2
WHERE T2.object = T1.object
AND T2."time stamp" < T1."time stamp"
ORDER BY T2."time stamp" DESC
LIMIT 1)
Creating a string from both values avoids having to use two subqueries.
This uses IS NOT instead of <> because the subquery will return NULL if no previous records exists.
EDIT: Retracting this after OP has further clarified what he desires. OP wants to gather rows representing a change of object state.
This would give you the unique set of object values
select distinct object, val1, val2
Do you need an arbitrary id and a timestamp to be associated with each row for a particular purpose? That is, do you want the first occurrence? the last occurrence? of the object-value1-value2 triad?
If so you could group:
select object, val1, val2, max(timestamp) as TS from T
group by object, val1, val2
Then if you needed the id that belonged to the triad with max(timestamp) you can join the inline view back to the table on the four values.
select t.id, foo.object, foo.val1, foo.val2, foo.TS
from t
join
(
select object, val1, val2, max(timestamp) as TS from T
group by object, val1, val2
) as foo
on t.object = foo.object and t.val1 = foo.val1 and t.val2 = foo.val2
and t.timestamp = foo.TS

SQL Server 2008 how to select top [column value] and random record?

I'm using SQL Server 2008, I want select random row record, and the total number of record is depend on another table's column value, how to do this?
My SQL statement is something like this, but wrong..
select top b.number a.name, a.link_id
from A a
left join B b on b.link_id = a.link_id
order by newid()
Here are my tables and the expected result.
Table A:
name link_id
james 100
albert 100
susan 100
simon 101
tom 101
fion 101
Table B:
link_id number
100 2
101 1
Expected result:
when run 1st time, result may be:
name link_id
james 100
susan 100
fion 101
2nd time result may be:
albert 100
susan 100
simon 101
3rd time could be:
james 100
albert 100
fion 101
Explaination
Refer to table B, link_id: 100, number: 2
meaning that Table A should select out 2 random record for link_id = 100
and need to select 1 random record for link_id=101
You can use the ROW_NUMBER() function:
SELECT A.name, A.link_id
FROM(
SELECT name,link_id, ROW_NUMBER()OVER(PARTITION BY link_id ORDER BY NEWID()) rn
FROM dbo.tblA
) AS A
JOIN dbo.tblB AS B
ON A.link_id = B.link_id
WHERE A.rn <= B.number;
Here is a SqlFiddle to show this in action: http://sqlfiddle.com/#!3/92eac/2
Try this:
SELECT a.*
FROM b
CROSS APPLY
(
SELECT TOP (b.number) a.*
FROM a
WHERE a.link_id = b.link_id
ORDER BY
NEWID()
) a
Also see: SQLFiddle

Resources