Is this T-SQL query correct? - tsql

My code returns a data set, however I do not believe they are accurate and I'm a bit lost working with sub queries. Can someone look over my code. The problem I'm trying to solve is from advanced question from T-SQL 2012 book. The question tells me:
Get the order ID, order date, customer ID, and company name for all orders that contain at least one item from the Condiments category. Use the category name in your query.
This is my code:
SELECT
o.orderid, o.orderdate, o.custid, c.companyname
FROM
Sales.Orders AS o
JOIN
Sales.OrderDetails AS od ON o.orderid = od.orderid
JOIN
Sales.Customers AS c ON o.custid = c.custid
WHERE
qty > 1
(SELECT categoryname FROM
Production.Categories
WHERE categoryname = N'Condiments');
My results:
orderid orderdate custid companyname
-------------------------------------------------------
10248 2006-07-04 00:00:00.000 85 Customer ENQZT
10248 2006-07-04 00:00:00.000 85 Customer ENQZT
10249 2006-07-05 00:00:00.000 79 Customer FAPSM
10250 2006-07-08 00:00:00.000 34 Customer IBVRG
Table structure:
Customers:
Sales.Customers
(
custid INT NOT NULL IDENTITY,
companyname NVARCHAR(40) NOT NULL,
contactname NVARCHAR(30) NOT NULL,
contacttitle NVARCHAR(30) NOT NULL
)
PK custid
Orders:
Sales.Orders
(
orderid INT NOT NULL IDENTITY,
custid INT NULL,
empid INT NOT NULL,
orderdate DATETIME NOT NULL
)
PK orderid
FK custid
Categories:
Production.Categories
(
categoryid INT NOT NULL IDENTITY,
categoryname NVARCHAR(15) NOT NULL,
description NVARCHAR(200) NOT NULL,
CONSTRAINT PK_Categories PRIMARY KEY(categoryid)
);
Orderdetails:
Sales.OrderDetails
(
orderid INT NOT NULL,
productid INT NOT NULL,
unitprice MONEY NOT NULL
CONSTRAINT DFT_OrderDetails_unitprice DEFAULT(0),
qty SMALLINT NOT NULL
)
I'm wrecking my head as this must be a correlated query because the Category table shares no relationship with Orders or Customers. Much appreciated for all learning/teaching responses.

There we go, your query should include the Products table, something like this:
SELECT o.orderid, o.orderdate, o.custid, c.companyname
FROM Sales.Orders AS o
JOIN Sales.OrderDetails AS od
ON o.orderid = od.orderid
JOIN Sales.Customers AS c
ON o.custid = c.custid
JOIN Production.Products d
on od.ProductId = d.ProductId
JOIN Production.Categories cat
on cat.CategoryId = d.CategoryID
and cat.categoryname = N'Condiments');
This may be enough to get you started.

Related

SQL Server recursive query with left outer join

I have two tables Customers and Orders with some data.
SELECT * FROM Customers C;
Result:
CustomerId Name
--------------------
1 Shree;
2 Kalpana;
3 Basavaraj;
Query:
select * from Orders O;
Result:
OrderId CustomerId OrderDate
-------------------------------------------------
100 1 2017-01-05 23:16:15.497
200 4 2017-01-06 23:16:15.497
300 3 2017-01-07 23:16:15.497
I have a business requirement where i need to populate data from Customers left outer join Orders in repeated way. I have written below query and desired data.
SELECT *
FROM Customers C
LEFT OUTER JOIN
(SELECT *
FROM Orders
WHERE OrderId = 100) O ON O.CustomerId = C.CustomerId
UNION ALL
SELECT *
FROM Customers C
LEFT OUTER JOIN
(SELECT *
FROM Orders
WHERE OrderId = 200) O ON O.CustomerId = C.CustomerId
UNION ALL
SELECT *
FROM Customers C
LEFT OUTER JOIN
(SELECT *
FROM Orders
WHERE OrderId = 300) O ON O.CustomerId = C.CustomerId;
Desired Result:
CustomerId Name OrderId CustomerId OrderDate
--------------------------------------------------------------------
1 Shree 100 1 2017-01-05 23:16:15.497
2 Kalpana NULL NULL NULL
3 Basavaraj NULL NULL NULL
1 Shree NULL NULL NULL
2 Kalpana NULL NULL NULL
3 Basavaraj NULL NULL NULL
1 Shree NULL NULL NULL
2 Kalpana NULL NULL NULL
3 Basavaraj 300 3 2017-01-07 23:16:15.497
I have one option to put left outer query in loop and pass the OrderId and finally save the result data but that takes lots of time because of high number of records. I want to know the best way to get this done. I have tried function and CTE but no luck so far. Please help.
Many thanks in advance.
A cartesian product can do the job:
SELECT C.*,
OrderId = CASE WHEN C.CustomerId = O.CustomerID THEN O.OrderId ELSE NULL END,
CustomerId = CASE WHEN C.CustomerId = O.CustomerID THEN O.CustomerId ELSE NULL END,
OrderDate = CASE WHEN C.CustomerId = O.CustomerID THEN O.OrderDate ELSE NULL END
FROM Orders O, Customers C
I have got the solution using similar to Cartesian product. Store the CustomerId in table variable and than make Cartesian production with same. This works as i wanted.
declare #CustomerTable TABLE (ID int IDENTITY(1,1) NOT NULL, CustomerId int);
insert into #CustomerTable select distinct CustomerId from orders;
select v.ID,isnull(v.CT_CustomerId,o.CustomerId) as CT_CustomerId,v.CustomerId,v.Name,o.* from
(select CT.ID,CT.CustomerId as CT_CustomerId,C.CustomerId,C.Name from #CustomerTable CT,Customers C ) V
left outer join Orders O ON O.CustomerId = V.CustomerId and V.ID=o.ID

Get value of at least one coincidense between related tables postgres

I have 3 tables:
CREATE TABLE public.student (id serial NOT NULL PRIMARY KEY,"student" varchar(30) NOT NULL) WITH (OIDS = FALSE);
CREATE TABLE public."class" (id serial NOT NULL PRIMARY KEY,"class" varchar(30) NOT NULL) WITH (OIDS = FALSE);
CREATE TABLE public.student_class (student_id integer, class_id integer, /* Keys */ CONSTRAINT student_class_index01
PRIMARY KEY (student_id, class_id)) WITH (OIDS = FALSE);
With these values:
INSERT INTO public.student_class ("student_id","class_id") VALUES(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(2,1),(2,2),(2,3),(3,4),(3,5),(3,6),(3,7),(3,8);
I want to now the names of the students that have at least one coincident class with other one:
Student 1 has got at least one coincidence with 2 and 3. Student 2 has
got at least one coincidence with 1. Student 3 has got at least one
coincidence with 1.
I have tried this, but it is not doing it by student.
SELECT distinct a.id,a.student from public.student a
LEFT OUTER JOIN public.student_class b ON b.student_id=a.id
LEFT OUTER JOIN public.class d ON d.id=b.class_id
WHERE class_id IN(select class_id from student_class where student_id not in(1))
AND a.id not in(1);
I think taht is easier than I think. Thanks.
What do you think about this :
with student_lst_classes as (
select student_id,array_agg(class_id order by class_id) lst_classes
from student_class group by 1
)
select st1.student,string_agg(st2.student,';' order by st2.student ASC) lst_student_coincident from
(student_lst_classes l1 join student st1 on (st1.id=l1.student_id))
,(student_lst_classes l2 join student st2 on (st2.id=l2.student_id))
where l1.student_id!=l2.student_id and l1.lst_classes && l2.lst_classes
group by 1 order by 1
Try this:
select *
from student
where exists (select null
from student_class sc1
where sc1.student_id = student.id
and exists (select null
from student_class sc2
where sc2.class_id = sc1.class_id
and sc2.student_id != sc1.student_id))
Besically a cartesian join of student X student, so there are no duplicates to take care of. (except for the symmetry s1 <--> s2)
SELECT s1.id AS a_id, s1.student AS a_student
, s2.id AS b_id, s2.student AS b_student
FROM student s1
JOIN student s2 ON EXISTS (
SELECT *
FROM student_class x1
JOIN student_class x2 ON x2.class_id = x1.class_id
WHERE x1.student_id = s1.id
AND x2.student_id = s2.id
)
WHERE s1.id < s2.id -- tie-breaker
;

How to calculate average date occurrence frequency in SQL

I'm trying to produce a query on the following table (relevant portion only):
Create Table [Order] (
OrderID int NOT NULL IDENTITY(1,1),
CreationDate datetime NOT NULL,
CustomerID int NOT NULL
)
I would like to see a list of CustomerIDs with each customer's average number of days between orders. I'm curious if this can be done with a pure set based solution or if a cursor/temp table solution is necessary.
;WITH base AS
(
SELECT CustomerID,
ROW_NUMBER() over (partition BY CustomerID ORDER BY CreationDate, OrderID) AS rn
FROM [Order]
)
SELECT b1.CustomerID,
AVG(DATEDIFF(DAY,b1.CreationDate, b2.CreationDate) )
FROM base b1
JOIN base b2
ON b1.CustomerID=b2.CustomerID
AND b2.rn =b1.rn+1
GROUP BY b1.CustomerID

Can I combine a PIVOT with an Inner join in microsoft SQL server?

I have the following SQL query:
SELECT CountryID, [10201] AS CountryGDPPerCapita, [10677] AS LifeExpTotal
FROM
(
SELECT CountryID,FieldID,numeric
FROM globaledge.dbo.DIBS_Data
WHERE CountryID IN (3,5)
AND FieldID IN (10201,10677)
AND year = 2002
) SourceTable
PIVOT
(
MAX(numeric)
FOR FieldID IN ([10201],[10677])
) AS PivotTable
ORDER BY PivotTable.CountryID
This returns something that looks like this:
CountryID CountryGDPPerCapita LifeExpTotal
3 35985.78 77.24
5 9147.7 74.54
Then I have another query as follows:
SELECT CountryName, CountryGDP, CountryGDPGrowth
FROM globaledge.dbo.Country_Statistics
WHERE CountryID IN (3,5)
AND year=2002
Order By CountryName
Which produces the following:
CountryName CountryGDP CountryGDPGrowth
Mexico 1567000000000000 1.3
United States 14440000000000000 0.4
Also note, I do have CountryID in both tables, that refer to the same country. What I want is to create one SQL Query, maybe with an INNER JOIN, that would return the following:
CountryName CountryGDP CountryGDPGrowth CountryGDPPerCapita LifeExpTotal
Mexico 156700000000000000 1.3 35985.78 77.24
United States 144400000000000000 0.4 9147.7 74.54
Could anyone help me make this query? or tell me if it's possible?
Something like this would work:
SELECT
a.CountryID, a.CountryName, a.CountryGDP, a.CountryGDPGrowth
, b.CountryGDPPerCapita, b.LifeExpTotal
FROM
(
SELECT CountryID, CountryName, CountryGDP, CountryGDPGrowth
FROM globaledge.dbo.Country_Statistics
WHERE CountryID IN (3,5)
AND year=2002
) AS a
JOIN
(
SELECT CountryID, [10201] AS CountryGDPPerCapita, [10677] AS LifeExpTotal
FROM
(
SELECT CountryID,FieldID,numeric
FROM globaledge.dbo.DIBS_Data
WHERE CountryID IN (3,5)
AND FieldID IN (10201,10677)
AND year = 2002
) SourceTable
PIVOT
(
MAX(numeric)
FOR FieldID IN ([10201],[10677])
) AS PivotTable
) AS b ON a.CountryID = b.CountryID
Order By a.CountryName

Cross Reference TSQL Join

Say i have Four tables
1) Studnets:
Student_ID
First Name
Last Name
2) Contact (Will take the latest item)
Contact_ID
Address
ZipCode
DateAdded
3) Phone (Will take the last three items)
Contact_ID
PhoneNumber
DateAdded
4) StudentContactRef
Student_ID
Contact_ID
How can I query this table? I want to have the fields as shows below:
Student_ID
First Name
Last Name
Address
ZipCode
PhoneNumber1
PhoneNumber2
PhoneNumber3
select
s.Student_ID,
s.FirstName,
s.LastName,
c.Contact_ID,
c.Address,
c.ZipCode,
p.PhoneNumber1,
p.PhoneNumber2,
p.PhoneNumber3
from
Students s
inner join StudentContactRef r on
s.Student_ID = r.StudentID
inner join Contact c on
r.Contact_ID = c.Contact_ID
inner join
(select top 3 Contact_ID, PhoneNumber from Phone
pivot (PhoneNumber for PhoneNumber IN
(PhoneNumber1, PhoneNumber2, PhoneNumber3)
where Contact_ID = r.Contact_ID order by DateAdded desc) p on
r.Contact_ID = p.Contact_ID
Update: That should get you what you're looking for!