使用外连接保留无法匹配的元组。
sql:
1)LEFT JOIN或LEFT OUTER JOIN
左向外联接的结果集包括 LEFT OUTER子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。 示例:
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
LEFT JOIN Orders
ON Persons.Id_P=Orders.Id_P
ORDER BY Persons.LastName
2)RIGHT JOIN 或 RIGHT OUTER JOIN
右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。
3)FULL JOIN 或 FULL OUTER JOIN
完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。
Hibernate中:
在hql里使用外连接必须先保证已经为表建立好外键关系。
例如每个鸟类活动(BirdActivitySituation)中记录一种鸟类(BaseBirdInfo),二者通过birdId进行关联。则在BirdActivitySituation.java中添加如下语句:
@OneToOne(targetEntity=BaseBirdInfo.class,cascade=CascadeType.ALL)
@Fetch(FetchMode.JOIN)
@JoinColumn(name="birdId",insertable=false,updatable=false)
private Set<BaseBirdInfo> baseBirdInfo=new LinkedHashSet<BaseBirdInfo>();
JPA中@JoinTable和@JoinColumn注解的使用:https://blog.csdn.net/yu870646595/article/details/51064634
注:此处因为原来已经有birdId属性,新增的关联birdId会出现重复,因此需要insertable=false,updatable=false
代码:
BirdActivitySituation.java
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
@Entity
@Table(name = "bird_activity_situation")
public class BirdActivitySituation implements java.io.Serializable{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer activityId;
private Integer airportId;
private Integer regionId;
private Integer birdId;//对应鸟类信息表birdId
private Integer familyId;
private String activityNum;
private String activityName;
private Date activityTime;
private String activitySite;
private String description;
private String windSpeed;
private String windDirection;
private String temperature;
private String humidity;
private String airVisibility;
private String weather;
private Date inTime;
private Date outTime;
private String birdCount;
private String flyDirection;
private String flyDirection1;
private String flyDirection2;
private String flySpeed;
private String flyStartPosition;
private String flyEndPosition;
private String frequency;
private String behavior;
private Integer flyHeight;
private String recorder;
private Date recordTime;
//以下关联鸟类信息表birdId
@OneToOne(targetEntity=BaseBirdInfo.class,cascade=CascadeType.ALL)
@Fetch(FetchMode.JOIN)
@JoinColumn(name="birdId",insertable=false,updatable=false)
private Set<BaseBirdInfo> baseBirdInfo=new LinkedHashSet<BaseBirdInfo>();//关联属性
public Set<BaseBirdInfo> getBirdActivityPoint() {
return baseBirdInfo;
}
public void setBirdActivityPoint(Set<BaseBirdInfo> birdActivityPoint) {
this.baseBirdInfo = birdActivityPoint;
}
//.........set和get方法等等.............
BaseBirdInfo .java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "base_bird_info")
public class BaseBirdInfo implements java.io.Serializable{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer birdId;
private Integer catalogId; //所在目、科*/
private String birdNum;
private String birdName;
private String pinyin;//拼音
private String eName;//英文名
private String lName;//拉丁名
private String migratory;//留居状况
private String activityAreas;//活动地带
private String conservation;//保护等级 分几等?
private String ecofeature;//生态特征
private String bodyLength;//体长
private String wingLength;//翅长
private String weight;//重量
private String integralColor;//总体颜色
private String headColor;//头部颜色
private String feathering;//有无羽饰
private Integer birdSequence;//排序
private Integer pictureAttachId;//图鉴
private Integer photoAttachId ;//照片
BirdActivityPointDaoImpl.java(记录鸟类出现坐标)
public List getPointCodeAndCorrespondBird(BasQueryForm qForm) {
Integer airportId = Integer.valueOf(qForm.getAirport());
String sql = "select a.activityId,p.pointId,b.birdId,substring(cast(p.code as string),1,2) as x,"
+ "substring(cast(p.code as string),3,2) as y,b.birdName "
+ "from BirdActivitySituation a left join a.baseBirdInfo b,BirdActivityPoint p where p.activityId = a.activityId ";
if(airportId != null)
sql += " and a.airportId="+airportId;
if(qForm.getStartDate() != null) {
sql += " and a.activityTime >='" + DateTimeTool.parseDateTime(qForm.getStartDate(), "yyyy-MM-dd") + " 00:00:00'";
}
if(qForm.getEndDate() != null) {
sql += " and a.activityTime <='" + DateTimeTool.parseDateTime(qForm.getEndDate(), "yyyy-MM-dd") + " 23:59:59'";
}
sql += " order by code";
List<Object[]> list = this.queryForList(sql);
List formList = new ArrayList<>();
if(list.size()>0) {
for(Object[] obj:list) {
BirdActivityPointForm form = new BirdActivityPointForm();
form.setActivityId(Integer.parseInt(obj[0].toString()));
form.setPointId(Integer.parseInt(obj[1].toString()));
if(obj[2]!=null && !obj[2].toString().equals(""))
form.setBirdId(Integer.parseInt(obj[2].toString()));
form.setX(Integer.parseInt(obj[3].toString()));
form.setY(Integer.parseInt(obj[4].toString()));
if(obj[5]!=null && !obj[5].toString().equals(""))
form.setBirdName(obj[5].toString());
formList.add(form);
}
}
return formList;
}