Issue:
I'm trying to return a list of contacts with a column containing all the parent item names concatenated together. Please don't bother telling me this violates 1st normal form, I already know. I've been trying to get this working for so long that it is probably some stupid mistake, but I need some help at this point.
Query:
SELECT C.ID, C.SequenceNumber, C.ContactType, C.GUID, C.ContactCategory, MAP.Parents, C.LastName, C.FirstName, C.CompanyName, C.Title, C.Email, C.Phone, C.MobilePhone, C.Fax, C.Comments, C.StandardConfirmation, C.Active FROM
(
SELECT ContactTypeMapping.Contact_GUID, STUFF( ( SELECT ','+ [NAME]
FROM ContactParents a
WHERE a.GUID =b.GUID
FOR XML PATH('')),1 ,1, '') Parents
FROM ContactParents b, ContactTypeMapping
WHERE ContactTypeMapping.Parent_GUID=b.GUID
) MAP
INNER JOIN
(
SELECT Contact.ID, Contact.GUID, Contact.SequenceNumber,
Contact.ContactType, Contact.ContactCategory, Contact.LastName, Contact.FirstName,
Contact.CompanyName, Contact.Title, Contact.Email, Contact.Phone,
Contact.MobilePhone, Contact.Fax, Contact.Comments, Contact.StandardConfirmation, Contact.Active
FROM Contact
)C
ON (MAP.Contact_GUID=C.GUID)
Current results:
ID SequenceNumber ContactType GUID ContactCategory Parents LastName FirstName CompanyName Title Email Phone MobilePhone Fax Comments StandardConfirmation Active
15 4 2 95A566D0-DB83-4853-9CB7-E6CF3B1FF814 0 AParent Beard Kirk NULL Business Kirk_Beard#someplace.com 913-906-3333 NULL (913) 906-3434 NULL 0 1
15 4 2 95A566D0-DB83-4853-9CB7-E6CF3B1FF814 0 AnotherParent Beard Kirk NULL Business Kirk_Beard#someplace.com 913-906-3333 NULL (913) 906-3434 NULL 0 1
Desired results:
15 4 2 95A566D0-DB83-4853-9CB7-E6CF3B1FF814 0 AParent,AnotherParent Beard Kirk NULL Business Kirk_Beard#someplace.com 913-906-3333 NULL (913) 906-3434 NULL 0 1
Data:
ContactParents Table:
GUID NAME TYPE
C40A6F7E-F760-48D6-8BAF-E55EC7DC900D AParent Place
A651A0A3-5A50-45F1-AB4B-2B7FDCE9734C AnotherParent Place
ContactTypeMapping Table:
Contact_GUID Parent_GUID ParentTable
95A566D0-DB83-4853-9CB7-E6CF3B1FF814 C40A6F7E-F760-48D6-8BAF-E55EC7DC900D Place
95A566D0-DB83-4853-9CB7-E6CF3B1FF814 A651A0A3-5A50-45F1-AB4B-2B7FDCE9734C Place
Contact Table:
ID GUID SequenceNumber ContactType LastName FirstName Title Email Phone MobilePhone Fax Comments Active ContactCategory CompanyName StandardConfirmation
15 95A566D0-DB83-4853-9CB7-E6CF3B1FF814 4 2 Beard Kirk Business Kirk_Beard#someplace.com 913-906-3333 NULL (913) 906-3434 NULL 1 0 NULL 0
;WITH cp AS -- contact parents - initial join
(
SELECT cp.NAME, ctm.Parent_GUID
FROM ContactParents AS cp
INNER JOIN ContactTypeMapping AS ctm
ON cp.GUID = ctm.Contact_GUID
),
cm AS -- contact mapping with concatenated values
(
SELECT Parent_GUID, Parents = (
SELECT STUFF ((SELECT ','+ [NAME] FROM cp AS cp2
WHERE cp2.Parent_GUID = cp.Parent_GUID
FOR XML PATH(''),
TYPE).value(N'./text()[1]',N'nvarchar(max)'),1 ,1, '')
)
FROM cp GROUP BY Parent_GUID
)
SELECT c.[GUID], cm.Parents --, other columns from c
FROM Contact AS c
INNER JOIN cm
ON c.[GUID] = cm.Parent_GUID;
To demonstrate how I verified that this query returns the right results, here are the table variables I created locally, how I populated them, and a slightly different query that references the table variables:
DECLARE #ContactParents TABLE
(
[GUID] UNIQUEIDENTIFIER,
NAME VARCHAR(32),
[TYPE] VARCHAR(32)
);
INSERT #ContactParents VALUES
('C40A6F7E-F760-48D6-8BAF-E55EC7DC900D','AParent','Place'),
('A651A0A3-5A50-45F1-AB4B-2B7FDCE9734C','AnotherParent','Place');
DECLARE #ContactTypeMapping TABLE
(
Contact_GUID UNIQUEIDENTIFIER,
Parent_GUID UNIQUEIDENTIFIER,
ParentTable VARCHAR(32)
);
INSERT #ContactTypeMapping VALUES
('A651A0A3-5A50-45F1-AB4B-2B7FDCE9734C','95A566D0-DB83-4853-9CB7-E6CF3B1FF814','Place'),
('C40A6F7E-F760-48D6-8BAF-E55EC7DC900D','95A566D0-DB83-4853-9CB7-E6CF3B1FF814','Place');
DECLARE #Contact TABLE
(
ID INT,
[GUID] UNIQUEIDENTIFIER,
LastName VARCHAR(32),
FirstName VARCHAR(32)
--, other columns...
);
INSERT #Contact VALUES
(15, '95A566D0-DB83-4853-9CB7-E6CF3B1FF814', 'Beard', 'Kirk');
;WITH cp AS
(
SELECT cp.NAME, ctm.Parent_GUID
FROM #ContactParents AS cp
INNER JOIN #ContactTypeMapping AS ctm
ON cp.GUID = ctm.Contact_GUID
),
cm AS
(
SELECT Parent_GUID, Parents = (
SELECT STUFF ((SELECT ','+ [NAME] FROM cp AS cp2
WHERE cp2.Parent_GUID = cp.Parent_GUID
FOR XML PATH('')),1 ,1, '')
)
FROM cp
GROUP BY Parent_GUID
)
SELECT c.[GUID], cm.Parents --, other columns from c
FROM #Contact AS c
INNER JOIN cm
ON c.[GUID] = cm.Parent_GUID;
Results
GUID Parents
95A566D0-DB83-4853-9CB7-E6CF3B1FF814 AParent,AnotherParent
Related
I have four tables in my Database which are related to each other.
document_category(document_category_id, document_category)
document_type(document_type_id, document_category.document_category_id, document_type)
student(student_id, f_name, l_name, ...other_columns)
student_document(id, student.student_id, document_type.document_type_id, file)
document_category, document_type, student and student_document
Table student_document stores uploaded documents. I want a query to display a list of documents that a student did not upload.
I have tried
(SELECT document_type FROM document_category JOIN document_type ON document_category.document_category_id = document_type.document_category_id
) LEFT JOIN(SELECT FILE FROM student_document JOIN student ON student.student_id = student_document.student_id) ON document_type.document_type_id = student_document.document_type_id
And I get an error
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LEFT JOIN(
SELECT FILE
FROM
student_document
JOIN student ON stud...' at line 8
I also tried this
SELECT * FROM document_type A LEFT JOIN student_document B ON A.document_type_id = B.document_type_id WHERE B.document_type_id is null
which gives me
Results, but I cannot get data for a specific student.
and the last one I tried is
SELECT student.email, student_document.file, document_type, document_category FROM student, document_type, document_category, student_document WHERE NOT EXISTS(SELECT * FROM student_document WHERE student_id = 'M054/T19' AND document_type_id ='20') AND student.student_id = student_document.student_id AND document_type.document_category_id = document_category.document_category_id
Which gives me Undesirable, and it is not what I want.
DECLARE #dc TABLE(dc_id Int, ctg VarChar(30));
INSERT INTO #dc VALUES (3,'Admission'),(5,'Payment');
DECLARE #dt TABLE (dt_id Int, dc_id Int, dtp VarChar(30));
INSERT INTO #dt VALUES (27,3, 'Admission Offer'),
(28,3,'Acceptance Letter');
DECLARE #s TABLE(s_id Int, f_name VarChar(30))
INSERT INTO #s VALUES (1, 'Marco'), (2, 'Mike')
DECLARE #sd TABLE (sd_id Int, s_id Int, dt_id Int, [file] VarChar(30))
INSERT INTO #sd VALUES (10,1,27,'File01');
SELECT dc.dc_id, ctg, dt.dt_id, dt.dtp, s.s_id, f_name FROM #dc dc
JOIN #dt dt ON dc.dc_id = dt.dc_id
CROSS APPLY #s s
-- All expected documents
dc_id ctg dt_id dtp s_id f_name
3 Admission 27 Admission Offer 1 Marco
3 Admission 27 Admission Offer 2 Mike
3 Admission 28 Acceptance Letter 1 Marco
3 Admission 28 Acceptance Letter 2 Mike
-- Provided documents
SELECT dc.dc_id, ctg, dt.dt_id, dt.dtp, s.s_id, f_name FROM #dc dc
JOIN #dt dt ON dc.dc_id = dt.dc_id
JOIN #sd sd ON sd.dt_id = dt.dt_id
JOIN #s s ON s.s_id = sd.s_id
dc_id ctg dt_id dtp s_id f_name
3 Admission 27 Admission Offer 1 Marco
-- Subtracting Set from Set
SELECT dc.dc_id, ctg, dt.dt_id, dt.dtp, s.s_id, f_name FROM #dc dc
JOIN #dt dt ON dc.dc_id = dt.dc_id
CROSS APPLY #s s
EXCEPT
SELECT dc.dc_id, ctg, dt.dt_id, dt.dtp, s.s_id, f_name FROM #dc dc
JOIN #dt dt ON dc.dc_id = dt.dc_id
JOIN #sd sd ON sd.dt_id = dt.dt_id
JOIN #s s ON s.s_id = sd.s_id
dc_id ctg dt_id dtp s_id f_name
3 Admission 27 Admission Offer 2 Mike
3 Admission 28 Acceptance Letter 1 Marco
3 Admission 28 Acceptance Letter 2 Mike
This code worked perfectly. The first query before WHERE NOT EXISTS retrieves the list of all required documents and student list, this details list of documents that a student has to upload. The second part retrieves the list of documents a student has upload.
So the query retrieves a list of required documents that are not present in the list of uploaded documents.
SELECT sp.student_id, do.document_type_id, do.document_type
FROM student_profile sp
CROSS JOIN document_type do
WHERE NOT EXISTS (SELECT sd.student_id, sd.document_type_id, d.document_type FROM student_document sd
INNER JOIN document_type d ON sd.document_type_id = d.document_type_id
WHERE do.document_type_id = sd.document_type_id
AND sp.student_id = sd.student_id );
I have two database tables customers which contains data about customers with the scheme like that:
mysql> SELECT * FROM customers;
customer_id created_at partner_id
1 "2019-08-20 09:17:58" cats
2 "2019-09-12 11:46:37" dogs
and customers_facts which keeps the customers facts in a form of fact_name and corresponding fact_value.
mysql> SELECT * FROM customers_facts;
customer_id fact_name fact_value
1, name Milton
1 city Milan
2 surname Bloom
2 name Orlando
I want to create a pivot table which in each row will have a customer and it's facts each as a separate column. Something like this:
mysql> SELECT * FROM pivot_table;
customer_id created_at partner_id name city surname
1 "2019-08-20 09:17:58" cats Milton Milan
2 "2019-09-12 11:46:37" dogs Orlando Bloom
I've found a script that allows me to create such table:
SET #sql = '';
SELECT
#sql := CONCAT(#sql,if(#sql='','',', '),temp.output)
FROM
(
SELECT
DISTINCT
CONCAT(
'MAX(IF(cf.fact_name = ''',
fact_name,
''', cf.fact_value, NULL)) AS ''',
fact_name,
''''
) as output
FROM
customers_facts
) as temp;
SET #sql = CONCAT('SELECT c.customer_id, c.created_at, c.partner_id, ', #sql, '
FROM customers c
LEFT JOIN customers_facts AS cf
ON cf.customer_id = c.customer_id
GROUP BY c.customer_id, c.created_at, c.partner_id');
but I have an issue of how to make it so:
a) I will be able to query the pivot table
b) When I add a new entry / update an old one in one of those two original tables the pivot table will be updated
How to solve ? Is it possible ?
Consider the following:
DROP TABLE IF EXISTS customers;
CREATE TABLE customers
(customer_id SERIAL PRIMARY KEY
,created_at DATETIME NOT NULL
,partner_id INT NOT NULL
);
INSERT INTO customers VALUES
(1,"2019-08-20 09:17:58",108),
(2,"2019-09-12 11:46:37",110);
DROP TABLE IF EXISTS customers_facts ;
CREATE TABLE customers_facts
(customer_id INT NOT NULL
,fact_name VARCHAR(20) NOT NULL
,fact_value VARCHaR(20) NOT NULL
,PRIMARY KEY(customer_id,fact_name)
);
INSERT INTO customers_facts VALUES
(1,'name','Milton'),
(1,'city','Milan'),
(2,'surname','Bloom'),
(2,'name','Orlando');
Now we can create a VIEW in the manner you describe...
DROP VIEW IF EXISTS my_pivot;
CREATE VIEW my_pivot AS
SELECT c.customer_id
, c.created_at
, c.partner_id
, MAX(CASE WHEN fact_name = 'name' THEN fact_value END) name
, MAX(CASE WHEN fact_name = 'surname' THEN fact_value END) surname
, MAX(CASE WHEN fact_name = 'city' THEN fact_value END) city
FROM customers c
LEFT
JOIN customers_facts f
ON f.customer_id = c.customer_id
GROUP
BY c.customer_id;
We can interrogate this VIEW with a simple query - e.g. SELECT customer_id FROM my_pivot WHERE name = 'Milton', however, this cannot use an index, so it's not very efficient.
Also, because of the way in which we created the VIEW, it cannot be updated...
UPDATE my_pivot SET name = 'Leonardo' WHERE customer_id = 1;
ERROR 1288 (HY000): The target table my_pivot of the UPDATE is not updatable
However, had we created the VIEW slightly differently, then it could be updated...
DROP VIEW IF EXISTS my_pivot;
CREATE VIEW my_pivot AS
SELECT c.customer_id
, c.created_at
, c.partner_id
, name.fact_value name
, surname.fact_value surname
, city.fact_value city
FROM customers c
LEFT
JOIN customers_facts name
ON name.customer_id = c.customer_id
AND name.fact_name = 'name'
LEFT
JOIN customers_facts surname
ON surname.customer_id = c.customer_id
AND surname.fact_name = 'surname'
LEFT
JOIN customers_facts city
ON city.customer_id = c.customer_id
AND city.fact_name = 'city';
UPDATE my_pivot SET name = 'Leonardo' WHERE customer_id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
SELECT * FROM customers_facts;
+-------------+-----------+------------+
| customer_id | fact_name | fact_value |
+-------------+-----------+------------+
| 1 | city | Milan |
| 1 | name | Leonardo |
| 2 | name | Orlando |
| 2 | surname | Bloom |
+-------------+-----------+------------+
...but this still cannot use an index.
EDIT: To answer the question asked in comments below your question, you can do...
SELECT customer_id
FROM customers_facts
WHERE
( fact_name,fact_value ) IN (('name','Orlando'),('surname','Bloom'))
GROUP
BY customer_id
HAVING COUNT(*) = 2;
...although I think MySQL can't use an index in this instance, so the longhand version might be better...
SELECT customer_id
FROM customers_facts
WHERE
( fact_name = 'name'
AND fact_value = 'Orlando'
)
OR
( fact_name = 'surname'
AND fact_value = 'Bloom'
)
GROUP
BY customer_id HAVING COUNT(*) = 2;
mysql,two tables:test(one) and review(many).
My goal:from review for one in the corresponding number
SELECT t.ID,t.TITLE,COALESCE(COUNT(r.ID),0) `count`
FROM `test` t
LEFT OUTER JOIN review r
ON t.ID = r.REVIEW_OBJ_ID
WHERE r.REVIEW_TYPE = '4'
ORDER BY `count` DESC;
Output:
ID TITLE count
402884f657e0a6d20157e0a82cc90000 brother 2
test table(A small portion of the data)
SELECT t.ID,t.TITLE
FROM `test` t;
Output:
ID TITLE
40284c8157ad8e7d0157ad8f86880000 1234567890123456789012345
402884f657e0a6d20157e0a82cc90000 brother
402884f657e0a6d20157e11967a20036 fg
402884f657e51eff0157e54cd8610004 AAA
402884f657e652fb0157e65642750000 BBB
0000000057f4dc900157f4ea9edd0000 VVV
00000000580065c5015800746d750000 CCC
00000000580065c501581d9f04f0000b TTT
And I want get this:
ID TITLE count
402884f657e0a6d20157e0a82cc90000 brother 2
402884f657e652fb0157e65642750000 BBB 0
00000000580065c501581d9f04f0000b TTT 0
402884f657e0a6d20157e11967a20036 fg 0
0000000057f4dc900157f4ea9edd0000 VVV 0
40284c8157ad8e7d0157ad8f86880000 1234567890123456789012345 0
402884f657e51eff0157e54cd8610004 AAA 0
00000000580065c5015800746d750000 CCC 0
so,I tried this and it worked:
SELECT t.ID,t.TITLE, COALESCE(r.c,0) `count`
FROM `test` t
LEFT OUTER JOIN
(
SELECT r.REVIEW_OBJ_ID obj_id, COUNT(r.ID) c
FROM review r,`test` t
WHERE r.REVIEW_TYPE = '4'
AND t.ID = r.REVIEW_OBJ_ID
) r ON r.obj_id = t.ID
ORDER BY `count` DESC;
But I have two questions:
It feels I can use one-time select to found out result,but I use two-times select.Can I optimize it?
Add a count(redundant) in the test table fields, whether it is a better choice.
/REVIEW_TYPE and REVIEW_OBJ_ID decide which object is reviewed,just like I use "REVIEW_TYPE='4'" to contact the test table/
drop table if exists user_doctor_review;
create table review
(
ID varchar(64) not null,
USER_ID varchar(64),
DOCTOR_ID varchar(64),
REVIEW_TYPE varchar(1),
REVIEW_OBJ_ID varchar(64),
SERVICE_SCORE int(6),
REVIEW_CONTENT varchar(600),
REVIEW_TIME datetime,
POID varchar(64),
IS_ANONYMITY varchar(1),
CHECKED_STATUS varchar(1),
STATUS varchar(1),
REPLY_CONTENT varchar(600),
REPLY_TIME datetime,
DOCTOR_IS_READ varchar(1),
primary key (ID)
);
Yes you can do it with one SELECT statement with this query
SELECT test.ID, test.TITLE, count(review.ID) as count from test
left join review on test.ID = review.REVIEW_OBJ_ID
where review.REVIEW_TYPE = 4 or review.ID is null
group by test.ID
I have created a SQL Fiddle here: http://sqlfiddle.com/#!9/c6a178/15
Explanation:
The key points are:
or review.ID is null
because it will make the query list the tests with no reviews, and
group by test.ID
this will get the correct review counts related to the test.
Results:
ID TITLE count
-------------------------------- ------------------------- -----
0000000057f4dc900157f4ea9edd0000 VVV 0
00000000580065c5015800746d750000 CCC 0
00000000580065c501581d9f04f0000b TTT 1
40284c8157ad8e7d0157ad8f86880000 1234567890123456789012345 0
402884f657e0a6d20157e0a82cc90000 brother 2
402884f657e0a6d20157e11967a20036 fg 0
402884f657e51eff0157e54cd8610004 AAA 0
402884f657e652fb0157e65642750000 BBB 0
I want to select all the customers that have the same name and birth date on mysql table.
my query right now is close, but it seems to have a flaw:
SELECT
id,
customer.name,
date
FROM
customer
INNER JOIN (
SELECT
name
FROM
customer
GROUP BY
name,date
HAVING
COUNT(id) > 1
) temp ON customer.name = customer.name
ORDER BY
name;
Return a customer if there EXISTS another one with same name and date, but other id:
SELECT
id,
name,
date
FROM
customer c1
where exists (SELECT 1 from customer c2
where c2.name = c1.name
and c2.date = c1.date
and c2.id <> c1.id)
JOIN version:
SELECT
c1.id,
c1.name,
c1.date
FROM
customer c1
JOIN customer c2
ON c2.name = c1.name
and c2.date = c1.date
and c2.id <> c1.id
You can do it using EXISTS expression:
SELECT
id,
customer.name,
date
FROM customer c
WHERE EXISTS (
SELECT *
FROM customer cc
WHERE cc.name=c.name AND cc.date=c.date AND cc.id <> c.id
)
The meaning of this query can be derived by pretending it's plain English: we are looking for all customers c for which there exists another customer cc with the same name and birth date, but different id.
Something like this should do it:
select
c1.*
from
customer c1
join customer c2 on
c1.name = c2.name
and c1.birth_date = c2.birth_date
and c1.id != c2.id
order by name, birth_date, id
;
And here's the full example:
drop table customer;
create table customer (
id int,
name varchar(64),
birth_date date
);
insert into customer values (1, 'Joe', '2001-01-01');
insert into customer values (2, 'Joe', '2001-01-02');
insert into customer values (3, 'Joe', '2001-01-03');
insert into customer values (4, 'Jim', '2001-01-01');
insert into customer values (5, 'Jack', '2001-01-01');
insert into customer values (6, 'George', '2001-01-01');
insert into customer values (7, 'George', '2001-01-02');
insert into customer values (8, 'Jeff', '2001-01-02');
insert into customer values (10, 'Joe', '2001-01-01');
insert into customer values (60, 'George', '2001-01-01');
select * from customer;
select
c1.*
from
customer c1
join customer c2 on
c1.name = c2.name
and c1.birth_date = c2.birth_date
and c1.id != c2.id
order by name, birth_date, id
;
+ ------- + --------- + --------------- +
| id | name | birth_date |
+ ------- + --------- + --------------- +
| 6 | George | 2001-01-01 |
| 60 | George | 2001-01-01 |
| 1 | Joe | 2001-01-01 |
| 10 | Joe | 2001-01-01 |
+ ------- + --------- + --------------- +
4 rows
Assuming a table with only id, name and date, you can expand it after that.
The solution is going to be in using an aliased join or an exists clause.
First some code to setup a temporary table with some values for us to query against.
--Drop Temporary Test Table if it exists
IF OBJECT_ID('tempdb.dbo.#Customers_Test', 'U') IS NOT NULL
DROP TABLE #Customers_Test;
--Create a Temporary Test Table
CREATE TABLE #Customers_Test
(
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NULL,
[date] [datetime] NULL,
CONSTRAINT [PK_Customers_Test] PRIMARY KEY CLUSTERED
(
[id] ASC
)
WITH
(
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON
) ON [PRIMARY]
) ON [PRIMARY]
--Put some temporary values into the table
INSERT INTO #Customers_Test(name, [date])
VALUES ('Joe', GETUTCDATE()),
('Mark', GETDATE()),
('Dan', '1/1/1990'),
('Dan', '1/1/1990')
Now for the actual selection styles, there are several ways to do this depending on mostly preferences, if this query had become more complex there may have been a significant run time advantage of one over another.
--First Select Version
SELECT #Customers_Test.id,
#Customers_Test.name,
#Customers_Test.[date]
FROM #Customers_Test
WHERE EXISTS (
SELECT 1
FROM #Customers_Test Duped_Customers
WHERE Duped_Customers.name = #Customers_Test.name
AND Duped_Customers.[date] = #Customers_Test.[date]
AND Duped_Customers.id <> #Customers_Test.id
)
Another way:
--Second Select Version
SELECT #Customers_Test.id,
#Customers_Test.name,
#Customers_Test.[date]
FROM #Customers_Test
INNER JOIN #Customers_Test AS Duped_Customers
ON #Customers_Test.name = Duped_Customers.name
AND #Customers_Test.[date] = Duped_Customers.[date]
AND #Customers_Test.id <> Duped_Customers.id
One Final Way:
--Third Select Version ( Similar to your current logic).
SELECT #Customers_Test.id,
#Customers_Test.name,
#Customers_Test.[date]
FROM #Customers_Test
WHERE #Customers_Test.name IN (
SELECT name
FROM #Customers_Test Duped_Customers
GROUP BY name, [date]
HAVING COUNT(name) > 1
)
I have a stored Procedure that I cant get to work:
ALTER PROCEDURE GetBrands
#sortColumn INT
AS
SELECT DISTINCT(tblBrand.BrandID),
tblBrandinCategory.CategoryID,
tblBrand.BrandName AS Brand,
AVG(tblReview.Grade) AS AverageGrade,
COUNT(tblReview.ReviewID) AS Review
FROM tblBrand LEFT JOIN
tblBrandinCategory ON tblBrand.BrandID = tblBrandinCategory.BrandID LEFT JOIN
tblReview ON tblBrand.BrandID = tblReview.BrandID
GROUP BY tblBrand.BrandID, tblBrandinCategory.CategoryID, tblBrand.BrandName
ORDER BY
CASE
WHEN #sortColumn = 1 THEN Brand
WHEN #sortColumn = 2 THEN Review
WHEN #sortColumn = 4 THEN AverageGrade
ELSE Brand
END
The result that I want to have is a list with brands, that only will be displayed once. The tblBrandInCategory messes that up for me.
tblBrand
BrandID BrandName
1 Nike
2 Adidas
3 Puma
tblCategory
CategoryID CategoryName
1 Shoes
2 Shorts
3 Pants
tblBrandInCategory
CategoryID BrandID
1 1
2 1
3 1
tblReview
ReviewID Grade BrandID
1 5 1
2 9 1
3 2 1
I get the result multiplyed with three becouse BrandID 1 exist 3 times in tblBrandInCategoiry.
Another problem is that in the ORDER BY CASE I get errors that AverageGrade is not recognizable, but tblReview.Grade is fine, but I want to order it on the Average Grade.
Another problem is that in the ORDER BY CASE I get errors that
AverageGrade is not recognizable, but tblReview.Grade is fine, but I
want to order it on the Average Grade.
AverageGrade can not be used as a column to sort until your main query is the Sub Query....
I get the result multiplyed with three becouse BrandID 1 exist 3 times
in tblBrandInCategoiry.
create table #tblBrand
(
BrandID int,
BrandName varchar(10)
)
create table #tblCategory
(
CategoryID int,
CategoryName varchar(10)
)
create table #tblBrandInCategory
(
CategoryID int,
BrandID int
)
create table #tblReview
(
ReviewID int,
Grade int,
BrandID int
)
insert into #tblBrand(BrandID, BrandName)values(1, 'Nike')
insert into #tblBrand(BrandID, BrandName)values(2, 'Adidas')
insert into #tblBrand(BrandID, BrandName)values(3, 'Puma')
insert into #tblCategory(CategoryID, CategoryName)values(1, 'Shoes')
insert into #tblCategory(CategoryID, CategoryName)values(2, 'Shorts')
insert into #tblCategory(CategoryID, CategoryName)values(3, 'Pants')
insert into #tblBrandInCategory(CategoryID, BrandID)values(1, 1)
insert into #tblBrandInCategory(CategoryID, BrandID)values(2, 1)
insert into #tblBrandInCategory(CategoryID, BrandID)values(3, 1)
insert into #tblReview(ReviewID, Grade, BrandID)values(1, 5, 1)
insert into #tblReview(ReviewID, Grade, BrandID)values(2, 5, 9)
insert into #tblReview(ReviewID, Grade, BrandID)values(3, 2, 1)
Select BrandID, Brand, AverageGrade, Review
From
(
SELECT DISTINCT(#tblBrand.BrandID),
--#tblBrandinCategory.CategoryID,
#tblBrand.BrandName AS Brand,
AVG(#tblReview.Grade) AS AverageGrade,
COUNT(#tblReview.ReviewID) AS Review
FROM #tblBrand
LEFT JOIN #tblBrandinCategory ON #tblBrand.BrandID = #tblBrandinCategory.BrandID
LEFT JOIN #tblReview ON #tblBrand.BrandID = #tblReview.BrandID
GROUP BY #tblBrand.BrandID, #tblBrandinCategory.CategoryID, #tblBrand.BrandName
)K
ORDER BY
CASE
WHEN #sortColumn = 1 THEN Brand
WHEN #sortColumn = 2 THEN Review
WHEN #sortColumn = 4 THEN AverageGrade
ELSE Brand
drop table #tblBrand
drop table #tblCategory
drop table #tblBrandInCategory
drop table #tblReview
Final Resultset
Just edit the SELECT to leave off tblBrandInCategory results:
SELECT tblBrand.BrandID,
tblBrand.BrandName AS Brand,
AVG(tblReview.Grade) AS AverageGrade,
COUNT(tblReview.ReviewID) AS Review
FROM tblBrand
--tblBrandinCategory isn't even needed for what you're doing
--LEFT JOIN tblBrandinCategory ON tblBrand.BrandID = tblBrandinCategory.BrandID
LEFT JOIN tblReview ON tblBrand.BrandID = tblReview.BrandID
GROUP BY tblBrand.BrandID, tblBrand.BrandName
This would need to be edited further to account for null joins, where a grade does not exist (maybe with AVG(ISNULL(tblReview.Grade, 0))). Depends on your requirements.