I am having some trouble with what I believe is a group by clause. I am trying to display a distinct CompanyID with the earliest InstallDate
Here is my code:
SELECT
Pa.PARTY_ID
,MIN(SM.[INSTALLDATE]) INSTALLDATE
,SM.[STOPDATE]
FROM FORMDESC FD
INNER JOIN STATEINFO SI
ON FD.FORMDESCID = SI.FORMDESCID
INNER JOIN COMPANY C
ON FD.COMPANYID = C.COMPANYID
INNER JOIN PARTY Pa
ON C.COMPANYFULLNAME = Pa.FULL_NM
INNER JOIN STATEMARKET SM
ON SI.STATEINFOID = SM.STATEINFOID
WHERE ENTIREFORMNUMBER = 'ABC123'
GROUP BY PARTY_ID, INSTALLDATE, STOPDATE
My current output is:
CompanyID | INSTALLDATE | STOPDATE
-------------------------------------------
60 | NULL | NULL
61 | 2015-09-26 00:00:00 | NULL
62 | NULL | NULL
62 | 2014-09-29 00:00:00 | NULL
62 | 2016-04-15 00:00:00 | NULL
The output I am seeking is:
CompanyID | INSTALLDATE | STOPDATE
----------------------------------------
60 | NULL | NULL
61 | 2015-09-26 00:00:00 | NULL
62 | 2014-09-29 00:00:00 | NULL
A left join on the SM table will not help me here either. If I pull any of the values from my group by clause, I get an error.
Is this a case where I should break this into a couple of selects instead?
While James Z's answer would indeed work; it was pointed out to me that my group by contained INSTALLDATE which caused my issue.
You probably need something like this:
select * from (
SELECT
Pa.PARTY_ID
,SM.[INSTALLDATE]
,SM.[STOPDATE]
,row_number() over (partition by Pa.PARTY_ID order by SM.[INSTALLDATE] desc) as RN
FROM FORMDESC FD
INNER JOIN STATEINFO SI
ON FD.FORMDESCID = SI.FORMDESCID
INNER JOIN COMPANY C
ON FD.COMPANYID = C.COMPANYID
INNER JOIN PARTY Pa
ON C.COMPANYFULLNAME = Pa.FULL_NM
INNER JOIN STATEMARKET SM
ON SI.STATEINFOID = SM.STATEINFOID
WHERE ENTIREFORMNUMBER = 'ABC123'
) X
where RN = 1
This will number the rows separately for each party_id, and then show the earliest one of them. This way you can get other data from the same row where the minimum value exists.
Related
I'm having an issue where I went all records in Table B and any non matching records in Table A but it's bringing back the matching records in Table A. There is another left join to an additional table which is brought in for reference only.
I'm using SSMS v18.
So ID will be on Table A and Table B. There will be multiple records of this ID on A and B but I don't want the duplicate records if date/time and ID is the same in Table A and in Table B.
e.g. - I've simplified the query I'm using below.
Select
a.id
a.datetime
a.emp_id
c.team_id
From
table_a as a
Left Join
table_b as b On a.id = b.id
And a.datetime <> b.datetime
Left Join
table_c On a.emp_id = c.emp_id
As there isn't NULLs I don't think I can use that. I don't believe a full outer join will return what I need.
Is there a method is solve this? A union query solution will not work as Table A and Table B do not have the same columns/column names.
Please let me know if more information is required.
EDIT - Additional
Apologies but now there's been a change of requirement where I now need to remove the matching records rather than remove just the duplicates. Is there a way around this?
Additional - Data Examples
Table A:
+----+------------------+--------+
| Id | Datetime | emp_id |
+----+------------------+--------+
| 1 | 20/04/2021 10:30 | a |
| 1 | 20/04/2021 11:15 | a |
| 2 | 21/04/2021 12:10 | b |
| 2 | 21/04/2021 13:20 | b |
| 2 | 22/04/2021 15:30 | c |
| 3 | 23/04/2021 09:45 | d |
| 4 | 23/04/2021 14:35 | e |
+----+------------------+--------+
Table B:
+----+------------------+-------------+
| Id | Datetime | other_field |
+----+------------------+-------------+
| 1 | 20/04/2021 10:30 | x |
| 2 | 21/04/2021 13:20 | y |
| 4 | 23/04/2021 14:35 | z |
+----+------------------+-------------+
Desired Output:
+----+------------------+--------+---------+
| Id | Datetime | emp_id | team_id |
+----+------------------+--------+---------+
| 1 | 20/04/2021 11:15 | a | team_01 |
| 2 | 21/04/2021 12:10 | b | team_02 |
| 2 | 22/04/2021 15:30 | c | team_01 |
| 3 | 23/04/2021 09:45 | d | team_02 |
+----+------------------+--------+---------+
So the duplicate ID & Datetime in Table B does not show in final output (regardless of any other fields)
You seem to need a right join instead of a left join. A left join will bring back all rows in table A, and all rows in table B which match the condition which you provided. You seem to want all in table B, which requires a right join.
I know some developers who have an aversion to right joins, if you feel that way, you can simply switch the order of the tables in your query to have table B listed first, left join to table A. I feel that the first solution is the easier one, though you need to be comfortable with it.
Here are my solutions, listed in the order in which I mentioned above.
Select
a.id
,a.datetime
,a.emp_id
,c.team_id
From
table_a as a
RIGHT Join -- here is my change
table_b as b On a.id = b.id
And a.datetime <> b.datetime
Left Join
table_c On a.emp_id = c.emp_id;
/*solution II*/
Select
a.id
,a.datetime
,a.emp_id
,c.team_id
From
table_b as b
Left Join
table_a as a On a.id = b.id
And a.datetime <> b.datetime
Left Join
table_c On a.emp_id = c.emp_id;
/*Updated solution, based on the comments (requirements seem to have changed)*/
Select
a.id
,a.datetime
,a.emp_id
,c.team_id
From
table_b as b
Left Join
table_a as a On a.id = b.id
Left Join
table_c On a.emp_id = c.emp_id
WHERE (a.datetime <> b.datetime OR b.datetime IS NULL);
Explanation of the updated solution: there was nothing to take into account the rows which would not match, hence the OR in the join
Please see Microsoft documentation on joins below.
https://learn.microsoft.com/en-us/sql/relational-databases/performance/joins?view=sql-server-ver15#:~:text=Joins%20indicate%20how%20SQL%20Server,be%20used%20for%20the%20join.
I am struggling with the following (apparently) easy task; my table (call it table1) look like this:
id | date | value
------------------
1 | 01 | 100
1 | 02 | 103
1 | 04 | 105
1 | 05 | 90
1 | 06 | 95
1 | 09 | 0
2 | 02 | 110
2 | 03 | 98
2 | 04 | 97
2 | 07 | 71
2 | 08 | 84
2 | 10 | 0
------------------
I would like to replace the two 0s with, respectively 95 and 84 (i.e. previous values in time). Any solution? I have been spending a looot of time on this (sorry but I am quite new to SQL)
Try this:
update table1 as a
set a.value=(select b.value
from table1 as b
where b.date<=a.date order by b.date desc limit 1)
where a.value=0;
Change to this
Make a new replica of table1 as table2 (same structure & same data in table1 and table2):
SET SQL_SAFE_UPDATES = 0;
update table1
set value=(select value
from table2
where table2.date<table1.date order by table2.date desc limit 1)
where table1.value=0;
Building up on nacho's query:
MySQL's update is a bit flawed. First: it doesn't accept an alias for the updated table. Second: It complains when you access the same table you want to update in the query. The latter can easily be solved by replacing from table1 b with from (select * from table1) b.
nacho's statement also missed to have the subquery refer to the same ID. And he mistakenly included the record itself (b.date <= instead of b.date <).
update table1
set value =
(
select b.value
from (select * from table1) b
where b.id = table1.id and b.date < table1.date
order by b.date desc limit 1
)
where value = 0;
And here is a test: http://rextester.com/YQV55035
UPDATE: You obviously tagged the wrong DBMS. Here is the same query for SQL Server:
update table1
set value =
(
select top(1) b.value
from table1 b
where b.id = table1.id and b.date < table1.date
order by b.date desc
)
where value = 0;
I have this query and i can't make it to concatanete the second column.
SELECT
Container.UIDaughterPlateId AS UIDaughterPlateId,
AllLastOperationInfo.OperationShortLabel AS lab
FROM
((InSite.UIDaughterPlate AS Container
INNER JOIN
InSite.UIDaughterPlateInfo AS UIDaughterPlateInfo ON (Container.UIDaughterPlateInfoId = UIDaughterPlateInfo.UIDaughterPlateInfoId ))
LEFT OUTER JOIN
(SELECT
UIOperationInfo.UIOperationInfoId as OperationInfoId,
UIOperationInfo.ParentId as DaughterPlateInfoId,
UIOperationInfo.Status as Status,
Operation.ShortLabel as OperationShortLabel,
UIOperationInfo.IsLast
FROM
UIOperationInfo
INNER JOIN
Operation ON Operation.OperationId = UIOperationInfo.UIOperationId
WHERE
UIOperationInfo.IsLast = 1 and Status = 'A RĂ©aliser') AllLastOperationInfo ON (UIDaughterPlateInfo.UIDaughterPlateInfoId = AllLastOperationInfo.DaughterPlateInfoId ))
ORDER BY
Container.UIDaughterPlateName DESC
The current results are
-------------------------
| UIDaughterPlateId | Lab |
|-------------------------|
| 42 | MD |
| 42 | MC |
| 47 | MC |
| 67 | MA |
| 67 | MB |
| 67 | MC |
-------------------------
And I want to have these results
-------------------------------
| UIDaughterPlateId | Lab |
|-------------------------------|
| 42 | MC MD |
| 47 | MC |
| 67 | MA MB MC |
-------------------------------
I've tried several examples that I found in other post but without success.
Can someone help me?
Thank you
You can try the following code:
-- Create demo data
CREATE TABLE #temp(UIDaughterPlateId int, Lab nvarchar(5))
INSERT INTO #temp(UIDaughterPlateId, Lab)
VALUES (42,N'MD'),(42, N'MC'),(47, N'MC'),(67, N'MA'),(67, N'MB'),(67, N'MC')
-- Your part:
SELECT DISTINCT t.UIDaughterPlateId, LEFT(dat.Lab,LEN(dat.Lab)-1) as Lab
FROM #temp AS t
OUTER APPLY (
SELECT s.Lab+N', '
FROM #temp as s
WHERE s.UIDaughterPlateId = t.UIDaughterPlateId
FOR XML PATH(N'')
) as dat(Lab)
-- Cleanup
DROP TABLE #temp
On the given input:
UIDaughterPlateId Lab
----------------- -----
42 MD
42 MC
47 MC
67 MA
67 MB
67 MC
This is the result of the query:
UIDaughterPlateId Lab
----------------- ----------
42 MD, MC
47 MC
67 MA, MB, MC
If you want to adapt it to your table structure just use a CTE for this.
WITH data AS(
-- your code from your question
SELECT
Container.UIDaughterPlateId AS UIDaughterPlateId,
AllLastOperationInfo.OperationShortLabel AS lab
FROM
((InSite.UIDaughterPlate AS Container
INNER JOIN
InSite.UIDaughterPlateInfo AS UIDaughterPlateInfo ON (Container.UIDaughterPlateInfoId = UIDaughterPlateInfo.UIDaughterPlateInfoId ))
LEFT OUTER JOIN
(SELECT
UIOperationInfo.UIOperationInfoId as OperationInfoId,
UIOperationInfo.ParentId as DaughterPlateInfoId,
UIOperationInfo.Status as Status,
Operation.ShortLabel as OperationShortLabel,
UIOperationInfo.IsLast
FROM
UIOperationInfo
INNER JOIN
Operation ON Operation.OperationId = UIOperationInfo.UIOperationId
WHERE
UIOperationInfo.IsLast = 1 and Status = 'A RĂ©aliser') AllLastOperationInfo ON (UIDaughterPlateInfo.UIDaughterPlateInfoId = AllLastOperationInfo.DaughterPlateInfoId ))
ORDER BY
Container.UIDaughterPlateName DESC
)
SELECT DISTINCT t.UIDaughterPlateId, LEFT(dat.Lab,LEN(dat.Lab)-1) as Lab
FROM data AS t
OUTER APPLY (
SELECT s.Lab+N', '
FROM data as s
WHERE s.UIDaughterPlateId = t.UIDaughterPlateId
FOR XML PATH(N'')
) as dat(Lab)
Create a view A using your current results, and execute
SELECT UIDaughterPlateId, replace(group_concat(lab),',',' ') AS lab FROM A GROUP BY UIDaughterPlateId
I have four tables:
Clients
ID | CLIENT_NUM | Year
Farms
ID | ClientID | FARM_NUM
Fields
ID | FarmID | FIELD_NUM | RANK
SoilSheet
ID | FarmID | FieldID | SAMP_NUM | Year
I need to get data from Soilsheet ordered by Rank, FIELD_NUM, and Year. So, I tried this:
SELECT FL.Rank,FL.FIELD_NUM, S.Year, SAMP_NUM
FROM (((SoilSheet S
INNER JOIN Farms F ON F.ID = S.FarmID)
INNER JOIN Clients C ON C.ID = F.ClientID)
INNER JOIN Fields FL ON FL.ID = S.FieldID)
WHERE C.CLIENT_NUM = 1 AND F.FARM_NUM = 1
ORDER BY C.CLIENT_NUM, F.FARM_NUM, FL.Rank, FL.FIELD_NUM, S.Year
The problem is RANK can be different in every year so it doesn't order properly. I need to have it order by RANK of the current year, 2015 for instance.
With the above, I get results like:
RANK | FIELD_NUM | Year | SAMP_NUM
0 | 19-2 | 2015 | 3000
2 | 20-1 | 2015 | 3001
2 | 20-1 | 2014 | 2002
2 | 20-1 | 2015 | 1003
20 | 19-2 | 2014 | 2001
19-2 is RANK 0 in 2015 but 20 in 2014. So, I tried this:
SELECT FL.Rank,FL.FIELD_NUM, S.Year, SAMP_NUM
FROM ((Clients C
INNER JOIN Farms F ON F.ClientID = C.ID)
INNER JOIN Fields FL ON FL.FarmID = F.ID)
LEFT JOIN (((SoilSheet S
INNER JOIN Fields FLS ON FLS.ID = S.FieldID)
INNER JOIN Farms FS ON FS.ID = S.FarmID)
INNER JOIN Clients CS ON CS.ID = FS.ClientID)
ON
(FLS.FIELD_NUM = FL.FIELD_NUM
AND FS.FARM_NUM = F.FARM_NUM
AND CS.CLIENT_NUM = C.CLIENT_NUM)
WHERE C.CLIENT_NUM = 1 AND F.FARM_NUM = 1 AND C.Year = 2015
ORDER BY C.CLIENT_NUM, F.FARM_NUM, FL.Rank, FL.FIELD_NUM, S.Year
This works fine in SQL Server:
RANK | FIELD_NUM | Year | SAMP_NUM
0 | 19-2 | 2015 | 3000
0 | 19-2 | 2014 | 2001
2 | 20-1 | 2015 | 3001
2 | 20-1 | 2014 | 2002
2 | 20-1 | 2015 | 1003
In Access, it gives 'Join expression not supported.'. I'm guessing it's because Access doesn't like joining on INNER joins but I'm just guessing.
Any Ideas? Another way to order or another way to join?
I finally got it to work
SELECT C1.Year,C1.RANK, C1.FIELD_NUM, C.CLIENT_NUM, F.FARM_NUM FROM
(SELECT C.Year,FL.RANK, FL.FIELD_NUM, C.CLIENT_NUM, F.FARM_NUM FROM
((Clients C
INNER JOIN Farms F ON F.ClientID = C.ID)
INNER JOIN Fields FL ON FL.FarmID = F.ID)) C1
LEFT JOIN
(SELECT S.Year, SAMP_NUM,FLS.FIELD_NUM, FS.FARM_NUM, CS.CLIENT_NUM
FROM ((SoilSheet S
INNER JOIN Fields FLS ON FLS.ID = S.FieldID)
INNER JOIN Farms FS ON FS.ID = S.FarmID)
INNER JOIN Clients CS ON CS.ID = FS.ClientID) S1
ON (S1.FIELD_NUM = C1.FIELD_NUM AND S1.FARM_NUM = C1.FARM_NUM
AND S1.CLIENT_NUM = C1.CLIENT_NUM)
WHERE C.CLIENT_NUM = 1 AND F.FARM_NUM = 1 AND C.Year = 2015
ORDER BY FL.Rank, FL.FIELD_NUM
Are you trying to copy the TSQL from SQL Server into Access? Unfortunately that won't work without modification to the Joins. Specifically, you will need to put parentheses around the join clauses.
Check out this for more information:
SQL Inner Joins with multiple tables
Please check the SQL schema and query on SQL Fiddle
I'm getting repetitive records with NULL values, if anyone can rectify the problem.
Regards
This is what I am getting:
| MEM_ID | MEM_EMAIL | GENDER | EDUCATION | PROFESSION |
|--------|----------------|--------|-----------|-------------|
| 1 | it#email.com | Male | (null) | (null) |
| 1 | it#email.com | (null) | Graduate | (null) |
| 1 | it#email.com | (null) | (null) | Engineer |
| 2 | info#email.com | Female | (null) | (null) |
| 2 | info#email.com | (null) | Graduate | (null) |
| 2 | info#email.com | (null) | (null) | Not Working |
but I need
| MEM_ID | MEM_EMAIL | GENDER | EDUCATION | PROFESSION |
|--------|----------------|--------|-----------|-------------|
| 1 | it#email.com | Male | Graduate | Engineer |
| 2 | info#email.com | Female | Graduate | Not Working |
|
Ah yes, the famous Inner-Platform effect, where you try to implement relations by creating "attribute-value" tables and assigning magic strings for data types and values, then try to retrieve values with massive self-joins at runtime.
Only madness lies down this road. SQL already includes features for enforcing key values and referential integrity; don't try to implement this yourself. It's especially frustrating because your schema is actually quite simple:
CREATE TABLE [dbo].Member(
ID INT PRIMARY KEY,
Email Varchar(50) NOT NULL,
GenderID INT NOT NULL,
EducationID INT,
ProfessionID INT
)
CREATE TABLE [dbo].Gender(
GenderID INT PRIMARY KEY,
GenderName Varchar(50) NOT NULL
)
CREATE TABLE [dbo].Education(
EducationID INT PRIMARY KEY,
EducationName Varchar(50) NOT NULL
)
CREATE TABLE [dbo].Profession(
ProfessionID INT PRIMARY KEY,
ProfessionName Varchar(50) NOT NULL
)
Assign your magic values to Gender, Education, and Profession rows and assign their IDs to Member. You can perform full lookups with a simple:
SELECT ID, Email, GenderName, EducationName, ProfessionName
FROM Member m
JOIN Gender g ON g.GenderID=m.GenderID
LEFT JOIN Education e ON e.EducationID=m.EducationID
LEFT JOIN Profession p ON p.ProfessionID=m.ProfessionID
WHERE ...
You want to enforce values? Make the Member columns NOT NULL. Want to allow, say, only a single instance of each Education row per member? Foreign-key constraints already support this, no need to invent your own query language.
I think you are basically trying to do a pivot on your data. This is one way to accomplish that.
SELECT M.mem_Id,
M.mem_email,
[Gender] = (select max( A.att_value)
from tbl_attributes A
inner join tbl_mem_att_values MAV
on MAV.att_id = A.att_id
inner join tbl_types T
on T.type_id = A.type_id
where T.type_name = 'Gender'
and MAV.mem_Id = M.mem_Id),
[Education] = (select max( A.att_value)
from tbl_attributes A
inner join tbl_mem_att_values MAV
on MAV.att_id = A.att_id
inner join tbl_types T
on T.type_id = A.type_id
where T.type_name = 'Education'
and MAV.mem_Id = M.mem_Id),
[Profession] = (select max( A.att_value)
from tbl_attributes A
inner join tbl_mem_att_values MAV
on MAV.att_id = A.att_id
inner join tbl_types T
on T.type_id = A.type_id
where T.type_name = 'Profession'
and MAV.mem_Id = M.mem_Id)
FROM tbl_members M
The result looks like this
EM_ID MEM_EMAIL GENDER EDUCATION PROFESSION
1 it#email.com Male Graduate Engineer
2 info#email.com Female Graduate Not Working
Here's what you need...
SQL Fiddle
SELECT M.mem_Id,
M.mem_email,
( SELECT AA.att_value
FROM tbl_mem_att_values mv
JOIN tbl_attributes AA ON AA.att_id = mv.att_id
JOIN tbl_types TG ON TG.type_name = 'Gender' AND TG.type_id = aa.type_id
WHERE mv.mem_id = M.mem_Id) AS Gender,
( SELECT AA.att_value
FROM tbl_mem_att_values mv
JOIN tbl_attributes AA ON AA.att_id = mv.att_id
JOIN tbl_types TG ON TG.type_name = 'Education' AND TG.type_id = aa.type_id
WHERE mv.mem_id = M.mem_Id) AS Education,
( SELECT AA.att_value
FROM tbl_mem_att_values mv
JOIN tbl_attributes AA ON AA.att_id = mv.att_id
JOIN tbl_types TG ON TG.type_name = 'Profession' AND TG.type_id = aa.type_id
WHERE mv.mem_id = M.mem_Id) AS Profession
FROM tbl_members M
Brad beat me by 6 seconds
Just as an alternative is you want to stick to the joins:
SELECT M.mem_Id,
M.mem_email,
AA.att_value AS Gender,
AB.att_value AS Education,
AC.att_value AS Profession
FROM tbl_members M
JOIN tbl_mem_att_values mavA ON M.mem_Id = mavA.mem_id
JOIN tbl_mem_att_values mavB ON M.mem_Id = mavB.mem_id
JOIN tbl_mem_att_values mavC ON M.mem_Id = mavC.mem_id
JOIN tbl_types TA ON TA.type_name = 'Gender'
JOIN tbl_types TB ON TB.type_name = 'Education'
JOIN tbl_types TC ON TC.type_name = 'Profession'
LEFT JOIN tbl_attributes AA ON mavA.att_id = AA.att_id AND TA.type_id = AA.type_id
LEFT JOIN tbl_attributes AB ON mavB.att_id = AB.att_id AND TB.type_id = AB.type_id
LEFT JOIN tbl_attributes AC ON mavC.att_id = AC.att_id AND TC.type_id = AC.type_id
WHERE AA.type_id IN (TA.type_id, TB.type_id, TC.type_id)
AND AB.type_id IN (TA.type_id, TB.type_id, TC.type_id)
AND AC.type_id IN (TA.type_id, TB.type_id, TC.type_id)