我的桌子上有这样的月份范围:
CREATE TABLE [dbo].[T_month_ranges](
[StartMonth] [datetime] NULL,
[EndMonth] [datetime] NULL
) ON [PRIMARY]
INSERT INTO [dbo].[T_month_ranges] ([StartMonth],[EndMonth]) VALUES
('2015-02-01','2015-04-01')
INSERT INTO [dbo].[T_month_ranges] ([StartMonth],[EndMonth]) VALUES
('2016-12-01','2017-02-01')
INSERT INTO [dbo].[T_month_ranges] ([StartMonth],[EndMonth]) VALUES
('2017-08-01','2017-09-01');
这些日期仅代表年月,第一天在这里并不重要。
现在我们需要创建select,它返回此表中日期之间的所有月份。所以在查询结果中会是这样的日期:
2015-02-01;2015-03-01;2015-04-01;2016-12-01;2017-01-01;2017-02-01;2017-08-01;2017-09-01
在sql server中实现此目的的最佳方法是什么?
答案 0 :(得分:2)
您可以使用递归CTE:
with m as (
select mr.startmonth as mon, mr.endmonth
from T_month_ranges mr
union all
select dateadd(month, 1, m.mon), m.endmonth
from m
where m.mon < m.endmonth
)
select m.mon
from m;
如果您的范围非常宽(几个月似乎不太可能),那么您可能需要将MAXRECURSION
选项设置为0.
替代方案 - 可能更快 - 是使用数字表:
with n as (
select row_number() over (order by (select null)) - 1 as n
from master..spt_values
)
select dateadd(month, n.n, mr.startmonth)
from T_month_ranges mr join
n
on dateadd(month, n.n, mr.startmonth) <= mr.endmonth;
答案 1 :(得分:0)
我经常使用TVF创建动态日期/时间范围。一个计数器/表也可以做到这一点。该函数是参数驱动的,您提供Range,DatePart和Increment
例如:
CREATE FUNCTION [dbo].[udf-Range-Date] (@R1 datetime,@R2 datetime,@Part varchar(10),@Incr int)
Returns Table
Return (
with cte0(M) As (Select 1+Case @Part When 'YY' then DateDiff(YY,@R1,@R2)/@Incr When 'QQ' then DateDiff(QQ,@R1,@R2)/@Incr When 'MM' then DateDiff(MM,@R1,@R2)/@Incr When 'WK' then DateDiff(WK,@R1,@R2)/@Incr When 'DD' then DateDiff(DD,@R1,@R2)/@Incr When 'HH' then DateDiff(HH,@R1,@R2)/@Incr When 'MI' then DateDiff(MI,@R1,@R2)/@Incr When 'SS' then DateDiff(SS,@R1,@R2)/@Incr End),
cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h ),
cte3(N,D) As (Select 0,@R1 Union All Select N,Case @Part When 'YY' then DateAdd(YY, N*@Incr, @R1) When 'QQ' then DateAdd(QQ, N*@Incr, @R1) When 'MM' then DateAdd(MM, N*@Incr, @R1) When 'WK' then DateAdd(WK, N*@Incr, @R1) When 'DD' then DateAdd(DD, N*@Incr, @R1) When 'HH' then DateAdd(HH, N*@Incr, @R1) When 'MI' then DateAdd(MI, N*@Incr, @R1) When 'SS' then DateAdd(SS, N*@Incr, @R1) End From cte2 )
Select RetSeq = N+1
,RetVal = D
From cte3,cte0
Where D<=@R2
)
/*
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS
Syntax:
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1)
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1)
*/
<强>返回强>
感兴趣的UDF。
Select A.*
,B.*
From T_month_ranges A
Cross Apply (
Select Top (DateDiff(MM,A.Startmonth,A.EndMonth)+1)
Date=DateAdd(MM,Row_Number() over (Order by (Select null)) - 1,A.Startmonth)
From master..spt_values
) B
选项2(没有UDF)
// @Based on the nice version of LucaZanini. Thank you!
public class IconPickerPreference extends ListPreference {
private int currentIndex = 0;
private class CustomListPreferenceAdapter extends ArrayAdapter<IconItem> {
private Context context;
private List<IconItem> icons;
private int resource;
public CustomListPreferenceAdapter(Context context, int resource, List<IconItem> objects) {
super(context, resource, objects);
this.context = context;
this.resource = resource;
this.icons = objects;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(resource, parent, false);
holder = new ViewHolder();
holder.iconName = (TextView) convertView.findViewById(R.id.iconName);
holder.iconImage = (ImageView) convertView.findViewById(R.id.iconImage);
holder.radioButton = (RadioButton) convertView.findViewById(R.id.iconRadio);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.iconName.setText(icons.get(position).name);
int identifier = context.getResources().getIdentifier( icons.get(position).file, "drawable", context.getPackageName());
holder.iconImage.setImageResource(identifier);
holder.radioButton.setChecked(icons.get(position).isChecked);
convertView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ViewHolder holder = (ViewHolder) v.getTag();
for (int i = 0; i < icons.size(); i++) {
if (i == position) {
icons.get(i).isChecked = true;
} else {
icons.get(i).isChecked = false;
}
}
getDialog().dismiss();
}
});
return convertView;
}
}
private class IconItem {
private String file;
private boolean isChecked;
private String name;
public IconItem(CharSequence name, CharSequence file, boolean isChecked) {
this(name.toString(), file.toString(), isChecked);
}
public IconItem(String name, String file, boolean isChecked) {
this.name = name;
this.file = file;
this.isChecked = isChecked;
}
}
private class ViewHolder {
protected ImageView iconImage;
protected TextView iconName;
protected RadioButton radioButton;
}
private Context context;
private ImageView icon;
private CharSequence[] iconFile;
private CharSequence[] iconName;
private List<IconItem> icons;
private SharedPreferences preferences;
private Resources resources;
private String selectedIconFile, defaultIconFile;
private TextView summary;
public IconPickerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
resources = context.getResources();
preferences = PreferenceManager.getDefaultSharedPreferences(context);
TypedArray a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.attrs_icon, 0, 0);
try {
defaultIconFile = a.getString(R.styleable.attrs_icon_iconFile);
} finally {
a.recycle();
}
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
CharSequence[] entries = getEntries();
CharSequence[] values = getEntryValues();
selectedIconFile = values[ currentIndex].toString();
icon = (ImageView) view.findViewById(R.id.iconSelected);
updateIcon();
summary = (TextView) view.findViewById( R.id.preference_summary);
summary.setText( entries[ currentIndex]);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (icons != null) {
for (int i = 0; i < iconName.length; i++) {
IconItem item = icons.get(i);
if (item.isChecked) {
persistString( "" + i);
currentIndex = i;
selectedIconFile = item.file;
updateIcon();
summary.setText(item.name);
break;
}
}
}
}
@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
String number = "0";
if (restorePersistedValue) {
// Restore existing state
number = this.getPersistedString( "0");
} else {
persistString( number);
}
try {
currentIndex = Integer.parseInt(number);
} catch( Exception e) {
; // skip any error, it will be corrected to 0
}
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
builder.setNegativeButton("Cancel", null);
builder.setPositiveButton(null, null);
iconName = getEntries();
iconFile = getEntryValues();
if (iconName == null || iconFile == null || iconName.length != iconFile.length) {
throw new IllegalStateException(
"IconPickerPreference requires an entries array and an entryValues array which are both the same length");
}
icons = new ArrayList<IconItem>();
for (int i = 0; i < iconName.length; i++) {
IconItem item = new IconItem(iconName[i], iconFile[i], ( i == currentIndex));
icons.add(item);
}
CustomListPreferenceAdapter customListPreferenceAdapter = new CustomListPreferenceAdapter(
context, R.layout.preference_list_icon_picker, icons);
builder.setAdapter(customListPreferenceAdapter, null);
}
private void updateIcon() {
int identifier = resources.getIdentifier( selectedIconFile, "drawable", context.getPackageName());
icon.setImageResource(identifier);
icon.setTag(selectedIconFile);
}
}