T-SQL在表格的日期之间生成月份

时间:2017-01-23 12:03:24

标签: sql-server sql-server-2008 tsql

我的桌子上有这样的月份范围:

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中实现此目的的最佳方法是什么?

2 个答案:

答案 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) 
*/

<强>返回

enter image description here

感兴趣的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);
    }
}